1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.mycore.frontend.cli;
20
21 import java.io.IOException;
22 import java.text.MessageFormat;
23 import java.util.Collection;
24 import java.util.List;
25 import java.util.Locale;
26
27 import org.jaxen.JaxenException;
28 import org.jdom2.Document;
29 import org.jdom2.Element;
30 import org.jdom2.Namespace;
31 import org.jdom2.filter.Filter;
32 import org.jdom2.filter.Filters;
33 import org.jdom2.xpath.XPathExpression;
34 import org.jdom2.xpath.XPathFactory;
35 import org.mycore.access.MCRAccessException;
36 import org.mycore.common.MCRConstants;
37 import org.mycore.common.MCRPersistenceException;
38 import org.mycore.common.config.MCRConfiguration2;
39 import org.mycore.common.content.MCRJDOMContent;
40 import org.mycore.common.xml.MCRNodeBuilder;
41 import org.mycore.datamodel.metadata.MCRMetadataManager;
42 import org.mycore.datamodel.metadata.MCRObject;
43 import org.mycore.datamodel.metadata.MCRObjectID;
44 import org.mycore.frontend.cli.annotation.MCRCommand;
45 import org.mycore.frontend.cli.annotation.MCRCommandGroup;
46
47
48
49
50
51
52
53
54 @MCRCommandGroup(name = "Batch Editor")
55 public class MCRBatchEditorCommands extends MCRAbstractCommands {
56
57 private static final Collection<Namespace> NS = MCRConstants.getStandardNamespaces();
58
59 private static final Filter<Element> FE = Filters.element();
60
61 private static final String CFG_PREFIX = "MCR.BatchEditor.";
62
63 private static final String CFG_PREFIX_BASE = CFG_PREFIX + "BaseLevel.";
64
65 private static final String CFG_SUFFIX_REMOVE = ".Path2Remove";
66
67 private static final String CFG_SUFFIX_ADD = ".Path2Add";
68
69 private enum Action {
70 ADD, ADD_IF, REMOVE, REMOVE_IF, REPLACE
71 }
72
73 @MCRCommand(syntax = "edit {0} at {1} add {2} {3}",
74 help = "Edit XML elements in object {0} at level {1} in object {1}, add field {2} with value {3}",
75 order = 2)
76 public static void batchAdd(String oid, String level, String field, String value)
77 throws JaxenException, MCRPersistenceException, MCRAccessException, IOException {
78 edit(oid, level, Action.ADD, field, value, null, null);
79 }
80
81 @MCRCommand(syntax = "edit {0} at {1} if {2} {3} add {4} {5}",
82 help = "Edit XML elements in object {0} at level {1}, if there is a field {2} with value {3}, "
83 + "add field {4} with value {5}",
84 order = 1)
85 public static void batchAddIf(String oid, String level, String fieldIf, String valueIf, String field2Add,
86 String value2Add)
87 throws JaxenException, MCRPersistenceException, MCRAccessException, IOException {
88 edit(oid, level, Action.ADD_IF, fieldIf, valueIf, field2Add, value2Add);
89 }
90
91 @MCRCommand(syntax = "edit {0} at {1} remove {2} {3}",
92 help = "Edit XML elements at in object {0} at level {1}, remove field {2} where value is {3}",
93 order = 2)
94 public static void batchRemove(String oid, String level, String field, String value)
95 throws MCRPersistenceException, MCRAccessException, JaxenException, IOException {
96 edit(oid, level, Action.REMOVE, field, value, null, null);
97 }
98
99 @MCRCommand(syntax = "edit {0} at {1} if {2} {3} remove {4} {5}",
100 help = "Edit XML elements in object {0} at level {1}, if there is a field {2} with value {3}, "
101 + "remove field {4} where value is {5}",
102 order = 1)
103 public static void batchRemoveIf(String oid, String level, String fieldIf, String valueIf, String field2Rem,
104 String value2Rem)
105 throws MCRPersistenceException, MCRAccessException, JaxenException, IOException {
106 edit(oid, level, Action.REMOVE_IF, fieldIf, valueIf, field2Rem, value2Rem);
107 }
108
109 @MCRCommand(syntax = "edit {0} at {1} replace {2} {3} with {4} {5}",
110 help = "Edit XML elements in object {0} at level {1}, replace field {2} value {3} by field {4} with value {5}",
111 order = 1)
112 public static void batchReplace(String oid, String level, String oldField, String oldValue, String newField,
113 String newValue)
114 throws JaxenException, MCRPersistenceException, MCRAccessException, IOException {
115 edit(oid, level, Action.REPLACE, oldField, oldValue, newField, newValue);
116 }
117
118 public static void edit(String oid, String level, Action a, String field1, String value1, String field2,
119 String value2)
120 throws JaxenException, MCRPersistenceException, MCRAccessException, IOException {
121 Document xmlOld = getObjectXML(oid);
122 Document xmlNew = xmlOld.clone();
123
124 for (Element base : getlevelElements(xmlNew, level)) {
125 if (a == Action.ADD) {
126 add(base, field1, value1);
127 } else if (a == Action.REMOVE) {
128 find(base, field1, value1).forEach(e -> e.detach());
129 } else if (a == Action.REPLACE) {
130 List<Element> found = find(base, field1, value1);
131 found.forEach(e -> e.detach());
132 if (!found.isEmpty()) {
133 add(base, field2, value2);
134 }
135 } else if (a == Action.ADD_IF) {
136 if (!find(base, field1, value1).isEmpty()) {
137 add(base, field2, value2);
138 }
139 } else if (a == Action.REMOVE_IF) {
140 if (!find(base, field1, value1).isEmpty()) {
141 find(base, field2, value2).forEach(e -> e.detach());
142 }
143 }
144 }
145
146 saveIfModified(xmlOld, xmlNew);
147 }
148
149 private static Document getObjectXML(String objectID) {
150 MCRObjectID oid = MCRObjectID.getInstance(objectID);
151 MCRObject obj = MCRMetadataManager.retrieveMCRObject(oid);
152 return obj.createXML();
153 }
154
155 private static void saveIfModified(Document xmlOld, Document xmlNew) throws MCRAccessException, IOException {
156 String oldData = new MCRJDOMContent(xmlOld).asString();
157 String newData = new MCRJDOMContent(xmlNew).asString();
158 if (!oldData.equals(newData)) {
159 MCRObject obj = new MCRObject(xmlNew);
160 MCRMetadataManager.update(obj);
161 }
162 }
163
164 private static List<Element> getlevelElements(Document xml, String level) {
165 String path = MCRConfiguration2.getStringOrThrow(CFG_PREFIX_BASE + level);
166 XPathExpression<Element> xPath = XPathFactory.instance().compile(path, FE, null, NS);
167 return xPath.evaluate(xml);
168 }
169
170 private static void add(Element base, String field, String value) throws JaxenException {
171 String path = MCRConfiguration2.getStringOrThrow(CFG_PREFIX + field + CFG_SUFFIX_ADD);
172 path = new MessageFormat(path, Locale.ROOT).format(new String[] { value });
173 new MCRNodeBuilder().buildNode(path, null, base);
174 }
175
176 private static List<Element> find(Element base, String field, String value) {
177 String path = MCRConfiguration2.getStringOrThrow(CFG_PREFIX + field + CFG_SUFFIX_REMOVE);
178 path = new MessageFormat(path, Locale.ROOT).format(new String[] { value });
179 XPathExpression<Element> fPath = XPathFactory.instance().compile(path, FE, null, NS);
180 List<Element> selected = fPath.evaluate(base);
181 return selected;
182 }
183 }