View Javadoc
1   package de.dlr.shepard.context.export;
2   
3   import com.fasterxml.jackson.databind.ObjectMapper;
4   import de.dlr.shepard.auth.users.entities.User;
5   import de.dlr.shepard.common.neo4j.io.AbstractDataObjectIO;
6   import de.dlr.shepard.common.neo4j.io.BasicEntityIO;
7   import de.dlr.shepard.context.collection.entities.Collection;
8   import de.dlr.shepard.context.collection.entities.DataObject;
9   import de.dlr.shepard.context.collection.io.CollectionIO;
10  import de.dlr.shepard.context.collection.io.DataObjectIO;
11  import de.dlr.shepard.context.labJournal.io.LabJournalEntryIO;
12  import de.dlr.shepard.context.references.basicreference.io.BasicReferenceIO;
13  import edu.kit.datamanager.ro_crate.RoCrate.RoCrateBuilder;
14  import edu.kit.datamanager.ro_crate.entities.contextual.PersonEntity;
15  import edu.kit.datamanager.ro_crate.entities.data.FileEntity;
16  import edu.kit.datamanager.ro_crate.entities.data.FileEntity.FileEntityBuilder;
17  import io.quarkus.logging.Log;
18  import java.io.ByteArrayInputStream;
19  import java.io.ByteArrayOutputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.time.LocalDateTime;
23  import java.time.ZoneId;
24  import java.time.format.DateTimeFormatter;
25  import java.util.ArrayList;
26  import java.util.Date;
27  import java.util.List;
28  import java.util.zip.ZipEntry;
29  import java.util.zip.ZipOutputStream;
30  import lombok.AccessLevel;
31  import lombok.Getter;
32  
33  public class ExportBuilder {
34  
35    private ObjectMapper objectMapper = new ObjectMapper();
36  
37    @Getter(value = AccessLevel.PROTECTED)
38    private RoCrateBuilder roCrateBuilder;
39  
40    private ByteArrayOutputStream baos;
41    private ZipOutputStream zos;
42    private List<String> entries;
43  
44    public ExportBuilder(Collection collection) throws IOException {
45      baos = new ByteArrayOutputStream();
46      zos = new ZipOutputStream(baos);
47      entries = new ArrayList<>();
48  
49      var roCrateName = collection.getName() + " Research Object Crate";
50      var roCrateDescription = "Research Object Crate representing the shepard Collection " + collection.getName();
51  
52      roCrateBuilder = new RoCrateBuilder().addName(roCrateName).addDescription(roCrateDescription);
53  
54      var collectionEntity = createFileEntity(new CollectionIO(collection));
55      roCrateBuilder.addDataEntity(collectionEntity);
56      addPersonEntity(collection.getCreatedBy());
57    }
58  
59    public ExportBuilder addDataObject(DataObject dataObject) throws IOException {
60      var dataObjectEntity = createFileEntity(new DataObjectIO(dataObject));
61      roCrateBuilder.addDataEntity(dataObjectEntity);
62      addPersonEntity(dataObject.getCreatedBy());
63      return this;
64    }
65  
66    public ExportBuilder addReference(BasicReferenceIO reference, User author) throws IOException {
67      var referenceEntity = createFileEntity(reference);
68      roCrateBuilder.addDataEntity(referenceEntity);
69      addPersonEntity(author);
70      return this;
71    }
72  
73    public ExportBuilder addLabJournalEntry(LabJournalEntryIO entry, User author) throws IOException {
74      var referenceEntity = createFileEntity(entry);
75      roCrateBuilder.addDataEntity(referenceEntity);
76      addPersonEntity(author);
77      return this;
78    }
79  
80    public ExportBuilder addPayload(byte[] payload, String filename, String name) throws IOException {
81      addToZip(filename, payload);
82      roCrateBuilder.addDataEntity(createFileEntityBuilder(filename, name).build());
83      return this;
84    }
85  
86    public ExportBuilder addPayload(byte[] payload, String filename, String name, String encodingFormat)
87      throws IOException {
88      addToZip(filename, payload);
89      roCrateBuilder.addDataEntity(createFileEntityBuilder(filename, name, encodingFormat).build());
90      return this;
91    }
92  
93    private void addPersonEntity(User user) {
94      if (user == null) return;
95  
96      var entity = new PersonEntity.PersonEntityBuilder()
97        .setId(user.getUsername())
98        .setEmail(user.getEmail())
99        .setGivenName(user.getFirstName())
100       .setFamilyName(user.getLastName())
101       .build();
102 
103     roCrateBuilder.addContextualEntity(entity);
104   }
105 
106   public InputStream build() throws IOException {
107     var roCrate = roCrateBuilder.build();
108     Object jsonObject = objectMapper.readValue(roCrate.getJsonMetadata(), Object.class);
109     byte[] bytes = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(jsonObject);
110     addToZip(ExportConstants.ROCRATE_METADATA, bytes);
111     zos.close();
112 
113     return new ByteArrayInputStream(baos.toByteArray());
114   }
115 
116   private FileEntity createFileEntity(AbstractDataObjectIO entity) throws IOException {
117     var filename = entity.getId() + ExportConstants.JSON_FILE_EXTENSION;
118     writeEntityToZip(filename, entity);
119     var fileEntityBuilder = createFileEntityBuilder(entity, filename);
120     fileEntityBuilder.addProperty(ExportConstants.DESCRIPTION_PROP, entity.getDescription());
121     return fileEntityBuilder.build();
122   }
123 
124   private FileEntity createFileEntity(LabJournalEntryIO entry) throws IOException {
125     var filename = entry.getId() + ExportConstants.JSON_FILE_EXTENSION;
126     writeEntityToZip(filename, entry);
127     var fileEntityBuilder = createFileEntityBuilder(entry, filename);
128     return fileEntityBuilder.build();
129   }
130 
131   private FileEntity createFileEntity(BasicReferenceIO entity) throws IOException {
132     var filename = entity.getId() + ExportConstants.JSON_FILE_EXTENSION;
133     writeEntityToZip(filename, entity);
134     var fileEntityBuilder = createFileEntityBuilder(entity, filename);
135     fileEntityBuilder.addProperty(ExportConstants.TYPE_PROP, entity.getType());
136     return fileEntityBuilder.build();
137   }
138 
139   private void writeEntityToZip(String filename, Object entity) throws IOException {
140     var bytes = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(entity);
141     addToZip(filename, bytes);
142   }
143 
144   private static FileEntityBuilder createFileEntityBuilder(String filename, String name) {
145     return new FileEntity.FileEntityBuilder().setId(filename).addProperty(ExportConstants.NAME_PROP, name);
146   }
147 
148   private static FileEntityBuilder createFileEntityBuilder(String filename, String name, String encodingFormat) {
149     var fileEntityBuilder = createFileEntityBuilder(filename, name);
150     fileEntityBuilder.addProperty("encodingFormat", encodingFormat);
151     return fileEntityBuilder;
152   }
153 
154   private static FileEntityBuilder createFileEntityBuilder(LabJournalEntryIO entry, String filename) {
155     var createdAt = convertToIsoDate(entry.getCreatedAt());
156     var type = entry.getClass().getSimpleName().replace("IO", "");
157     var fileEntityBuilder = new FileEntity.FileEntityBuilder().setId(filename);
158     fileEntityBuilder.addProperty("encodingFormat", "application/json");
159     fileEntityBuilder
160       .addAuthor(entry.getCreatedBy())
161       .addProperty(ExportConstants.CREATED_PROP, createdAt)
162       .addProperty(ExportConstants.TYPE_PROP, type);
163     return fileEntityBuilder;
164   }
165 
166   private static FileEntityBuilder createFileEntityBuilder(BasicEntityIO entity, String filename) {
167     var createdAt = convertToIsoDate(entity.getCreatedAt());
168     var type = entity.getClass().getSimpleName().replace("IO", "");
169     var fileEntityBuilder = createFileEntityBuilder(filename, entity.getName(), "application/json");
170     fileEntityBuilder
171       .addAuthor(entity.getCreatedBy())
172       .addProperty(ExportConstants.CREATED_PROP, createdAt)
173       .addProperty(ExportConstants.TYPE_PROP, type);
174     if (entity.getUpdatedAt() != null) fileEntityBuilder.addProperty(
175       ExportConstants.UPDATED_PROP,
176       convertToIsoDate(entity.getUpdatedAt())
177     );
178 
179     return fileEntityBuilder;
180   }
181 
182   private static String convertToIsoDate(Date dateToConvert) {
183     var localDateTime = LocalDateTime.ofInstant(dateToConvert.toInstant(), ZoneId.systemDefault());
184     return DateTimeFormatter.ISO_DATE_TIME.format(localDateTime);
185   }
186 
187   private void addToZip(String filename, byte[] bytes) throws IOException {
188     if (entries.contains(filename)) {
189       Log.warnf("%s already in zip file, skipping", filename);
190       return;
191     }
192 
193     zos.putNextEntry(new ZipEntry(filename));
194     zos.write(bytes);
195     zos.closeEntry();
196     entries.add(filename);
197   }
198 }