Skip to content

Commit 22ceea5

Browse files
committed
added new restore method restoreXML() (Issue #954)
1 parent 191a2a8 commit 22ceea5

2 files changed

Lines changed: 90 additions & 44 deletions

File tree

imixs-workflow-engine/src/main/java/org/imixs/workflow/engine/DocumentService.java

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.imixs.workflow.exceptions.InvalidAccessException;
4444
import org.imixs.workflow.exceptions.PluginException;
4545
import org.imixs.workflow.exceptions.QueryException;
46+
import org.imixs.workflow.xml.XMLDataCollectionAdapter;
4647

4748
import jakarta.annotation.Resource;
4849
import jakarta.annotation.security.DeclareRoles;
@@ -57,6 +58,7 @@
5758
import jakarta.persistence.FlushModeType;
5859
import jakarta.persistence.PersistenceContext;
5960
import jakarta.persistence.Query;
61+
import jakarta.xml.bind.JAXBException;
6062

6163
/**
6264
* The DocumentService is used to save and load instances of ItemCollections
@@ -1160,7 +1162,7 @@ public void restore(String filePath) throws IOException {
11601162

11611163
FileInputStream fis = new FileInputStream(filePath);
11621164
ObjectInputStream in = new ObjectInputStream(fis);
1163-
logger.log(Level.INFO, "...starting restor form file {0}...", filePath);
1165+
logger.log(Level.INFO, "├── starting restore form file {0}...", filePath);
11641166
long l = System.currentTimeMillis();
11651167
while (true) {
11661168
try {
@@ -1177,7 +1179,7 @@ public void restore(String filePath) throws IOException {
11771179
icount++;
11781180
if (icount >= JUNK_SIZE) {
11791181
icount = 0;
1180-
logger.log(Level.INFO, "...restored {0} document in {1}ms....",
1182+
logger.log(Level.INFO, "├── restored {0} document in {1}ms....",
11811183
new Object[] { totalcount, System.currentTimeMillis() - l });
11821184
l = System.currentTimeMillis();
11831185
}
@@ -1186,22 +1188,67 @@ public void restore(String filePath) throws IOException {
11861188
break;
11871189
} catch (ClassNotFoundException e) {
11881190
errorCount++;
1189-
logger.log(Level.WARNING, "...error importing workitem at position {0}{1} Error: {2}",
1191+
logger.log(Level.WARNING, "└── error importing workitem at position {0}{1} Error: {2}",
11901192
new Object[] { totalcount, errorCount, e.getMessage() });
11911193
} catch (AccessDeniedException e) {
11921194
errorCount++;
1193-
logger.log(Level.WARNING, "...error importing workitem at position {0}{1} Error: {2}",
1195+
logger.log(Level.WARNING, "└── error importing workitem at position {0}{1} Error: {2}",
11941196
new Object[] { totalcount, errorCount, e.getMessage() });
11951197
}
11961198
}
11971199
in.close();
11981200

1199-
String loginfo = "Import successfull! " + totalcount + " Entities imported. " + errorCount
1201+
String loginfo = "└── restore successfull! " + totalcount + " Entities imported. " + errorCount
12001202
+ " Errors. Import FileName:" + filePath;
12011203

12021204
logger.info(loginfo);
12031205
}
12041206

1207+
/**
1208+
* This method restores a backup from an XML file and imports the documents into
1209+
* the database.
1210+
*
1211+
* @param filePath path to the XML backup file
1212+
* @throws IOException
1213+
*/
1214+
public void restoreXML(String filePath) throws IOException {
1215+
int JUNK_SIZE = 100;
1216+
long totalcount = 0;
1217+
long errorCount = 0;
1218+
long l = System.currentTimeMillis();
1219+
1220+
logger.log(Level.INFO, "├── starting XML restore from file {0}...", filePath);
1221+
1222+
try (FileInputStream fis = new FileInputStream(filePath)) {
1223+
List<ItemCollection> documents = XMLDataCollectionAdapter.readCollectionFromInputStream(fis);
1224+
if (documents == null || documents.isEmpty()) {
1225+
logger.warning("└── no documents found in XML file: " + filePath);
1226+
return;
1227+
}
1228+
for (ItemCollection itemCol : documents) {
1229+
try {
1230+
itemCol.removeItem(VERSION);
1231+
ctx.getBusinessObject(DocumentService.class).saveByNewTransaction(itemCol);
1232+
totalcount++;
1233+
if (totalcount % JUNK_SIZE == 0) {
1234+
logger.log(Level.INFO, "├── restored {0} documents in {1}ms....",
1235+
new Object[] { totalcount, System.currentTimeMillis() - l });
1236+
l = System.currentTimeMillis();
1237+
}
1238+
} catch (AccessDeniedException e) {
1239+
errorCount++;
1240+
logger.log(Level.WARNING, "└── error importing document at position {0} Error: {1}",
1241+
new Object[] { totalcount + errorCount, e.getMessage() });
1242+
}
1243+
}
1244+
} catch (JAXBException e) {
1245+
throw new IOException("Failed to parse XML file: " + e.getMessage(), e);
1246+
}
1247+
1248+
logger.log(Level.INFO, "└── XML restore successful! {0} documents imported. {1} errors. File: {2}",
1249+
new Object[] { totalcount, errorCount, filePath });
1250+
}
1251+
12051252
/**
12061253
* Verifies if the caller has write access to the current ItemCollection
12071254
*

imixs-workflow-jax-rs/src/main/java/org/imixs/workflow/jaxrs/DocumentRestService.java

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,31 @@
1515

1616
package org.imixs.workflow.jaxrs;
1717

18-
import jakarta.annotation.Resource;
19-
import jakarta.ejb.SessionContext;
2018
import java.io.IOException;
2119
import java.io.OutputStream;
2220
import java.io.UnsupportedEncodingException;
2321
import java.net.URLDecoder;
2422
import java.util.ArrayList;
2523
import java.util.List;
26-
import java.util.StringTokenizer;
27-
import java.util.Vector;
24+
import java.util.logging.Level;
2825
import java.util.logging.Logger;
2926

27+
import org.imixs.workflow.ItemCollection;
28+
import org.imixs.workflow.WorkflowKernel;
29+
import org.imixs.workflow.engine.DocumentService;
30+
import org.imixs.workflow.engine.index.SchemaService;
31+
import org.imixs.workflow.engine.index.SearchService;
32+
import org.imixs.workflow.exceptions.AccessDeniedException;
33+
import org.imixs.workflow.exceptions.ImixsExceptionHandler;
34+
import org.imixs.workflow.exceptions.QueryException;
35+
import org.imixs.workflow.xml.XMLCount;
36+
import org.imixs.workflow.xml.XMLDataCollectionAdapter;
37+
import org.imixs.workflow.xml.XMLDocument;
38+
import org.imixs.workflow.xml.XMLDocumentAdapter;
39+
40+
import jakarta.annotation.Resource;
41+
import jakarta.ejb.SessionContext;
42+
import jakarta.ejb.Stateless;
3043
import jakarta.inject.Inject;
3144
import jakarta.ws.rs.Consumes;
3245
import jakarta.ws.rs.DELETE;
@@ -44,23 +57,6 @@
4457
import jakarta.ws.rs.core.Response;
4558
import jakarta.ws.rs.core.StreamingOutput;
4659

47-
import org.imixs.workflow.ItemCollection;
48-
import org.imixs.workflow.WorkflowKernel;
49-
import org.imixs.workflow.engine.DocumentService;
50-
import org.imixs.workflow.engine.index.SchemaService;
51-
import org.imixs.workflow.engine.index.SearchService;
52-
import org.imixs.workflow.exceptions.AccessDeniedException;
53-
import org.imixs.workflow.exceptions.ImixsExceptionHandler;
54-
import org.imixs.workflow.exceptions.QueryException;
55-
import org.imixs.workflow.xml.XMLCount;
56-
import org.imixs.workflow.xml.XMLDataCollectionAdapter;
57-
import org.imixs.workflow.xml.XMLDocument;
58-
import org.imixs.workflow.xml.XMLDocumentAdapter;
59-
60-
import jakarta.ejb.Stateless;
61-
import jakarta.servlet.http.HttpServletRequest;
62-
import java.util.logging.Level;
63-
6460
/**
6561
* The DocumentService provides methods to access the DocumentService EJB
6662
*
@@ -162,15 +158,15 @@ public Response getDocument(@PathParam("uniqueid") String uniqueid, @QueryParam(
162158
document = documentService.load(uniqueid);
163159
if (document == null) {
164160
// document not found
165-
return Response.status(Response.Status.NOT_FOUND).build();
161+
return Response.status(Response.Status.NOT_FOUND).build();
166162
}
167163
} catch (Exception e) {
168164
e.printStackTrace();
169165
return null;
170166
}
171167
return convertResult(document, items, format);
172168
}
173-
169+
174170
/**
175171
* Returns a resultset for a lucene Search Query
176172
*
@@ -210,10 +206,10 @@ public Response findDocumentsByQuery(@PathParam("query") String query,
210206
/**
211207
* Returns a resultset for a JPQL statement
212208
*
213-
* @param query - JPQL statement
214-
* @param pageSize - page size
209+
* @param query - JPQL statement
210+
* @param pageSize - page size
215211
* @param pageIndex - page index (default = 0)
216-
* @param items - optional list of items
212+
* @param items - optional list of items
217213
* @return result set.
218214
*/
219215
@GET
@@ -384,7 +380,8 @@ public Response postDocument(XMLDocument xmlworkitem, @QueryParam("items") Strin
384380
// return workitem
385381
try {
386382
if (workitem.hasItem("$error_code")) {
387-
logger.log(Level.SEVERE, "{0}: {1}", new Object[]{workitem.getItemValueString("$error_code"), workitem.getItemValueString("$error_message")});
383+
logger.log(Level.SEVERE, "{0}: {1}", new Object[] { workitem.getItemValueString("$error_code"),
384+
workitem.getItemValueString("$error_message") });
388385
return Response.ok(XMLDataCollectionAdapter.getDataCollection(workitem), MediaType.APPLICATION_XML)
389386
.status(Response.Status.NOT_ACCEPTABLE).build();
390387
} else {
@@ -441,22 +438,22 @@ public Response deleteEntity(@PathParam("uniqueid") String uniqueid) {
441438
*
442439
*
443440
* @param query
444-
* @param filepath - path in server filesystem
441+
* @param filepath - path in server filesystem
445442
* @param snapshots - opitonal backup snapshots only
446443
* @return
447444
*/
448445
@PUT
449446
@Path("/backup/{query}")
450447
public Response backup(@PathParam("query") String query, @QueryParam("filepath") String filepath,
451448
@QueryParam("snapshots") boolean snapshots) {
452-
449+
453450
if (ctx.isCallerInRole("org.imixs.ACCESSLEVEL.MANAGERACCESS") == false) {
454451
return Response.status(Response.Status.UNAUTHORIZED).build();
455452
}
456453
try {
457454
// decode query...
458455
String decodedQuery = URLDecoder.decode(query, "UTF-8");
459-
documentService.backup(decodedQuery, filepath,snapshots);
456+
documentService.backup(decodedQuery, filepath, snapshots);
460457
} catch (IOException e) {
461458
e.printStackTrace();
462459
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
@@ -470,27 +467,31 @@ public Response backup(@PathParam("query") String query, @QueryParam("filepath")
470467
}
471468

472469
/**
473-
* This method restores a backup from the fileSystem
470+
* This method restores a backup from the fileSystem. Supports both serialized
471+
* Java object streams and XML format.
474472
*
475473
* @param filepath - path in server fileSystem
476474
* @return
477475
*/
478476
@GET
479477
@Path("/restore")
480478
public Response restore(@QueryParam("filepath") String filepath) {
481-
482479
if (ctx.isCallerInRole("org.imixs.ACCESSLEVEL.MANAGERACCESS") == false) {
483480
return Response.status(Response.Status.UNAUTHORIZED).build();
484481
}
485482
try {
486-
documentService.restore(filepath);
483+
if (filepath != null && filepath.toLowerCase().endsWith(".xml")) {
484+
documentService.restoreXML(filepath);
485+
} else {
486+
documentService.restore(filepath);
487+
}
487488
} catch (IOException e) {
488489
e.printStackTrace();
489-
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
490+
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
491+
.entity(e.getMessage())
492+
.build();
490493
}
491-
492494
return Response.status(Response.Status.OK).build();
493-
494495
}
495496

496497
/**
@@ -511,8 +512,6 @@ public Response getConfiguration(@QueryParam("format") String format) throws Exc
511512
return convertResult(config, null, format);
512513
}
513514

514-
515-
516515
/**
517516
* This method converts a single ItemCollection into a Jax-rs response object.
518517
* <p>
@@ -527,7 +526,7 @@ public Response getConfiguration(@QueryParam("format") String format) throws Exc
527526
*/
528527
public Response convertResult(ItemCollection workitem, String items, String format) {
529528
if (workitem == null) {
530-
return Response.status(Response.Status.NOT_FOUND).build();
529+
return Response.status(Response.Status.NOT_FOUND).build();
531530
}
532531
if ("json".equals(format)) {
533532
return Response

0 commit comments

Comments
 (0)