1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.importexport.command;
35
36 import info.magnolia.commands.impl.BaseRepositoryCommand;
37 import info.magnolia.context.Context;
38 import info.magnolia.importexport.DataTransporter;
39 import info.magnolia.jcr.util.NodeTypes;
40 import info.magnolia.jcr.util.NodeUtil;
41 import info.magnolia.jcr.util.PropertyUtil;
42 import info.magnolia.module.delta.BootstrapFileUtil;
43
44 import java.io.InputStream;
45 import java.io.InputStreamReader;
46 import java.util.Arrays;
47 import java.util.Collection;
48 import java.util.HashMap;
49 import java.util.Map;
50
51 import javax.jcr.ImportUUIDBehavior;
52 import javax.jcr.Node;
53 import javax.jcr.PropertyType;
54 import javax.jcr.RepositoryException;
55 import javax.jcr.ValueFactory;
56
57 import org.apache.commons.io.FilenameUtils;
58 import org.apache.commons.lang3.StringUtils;
59 import org.apache.jackrabbit.JcrConstants;
60 import org.apache.jackrabbit.core.NodeImpl;
61 import org.apache.jackrabbit.value.ValueHelper;
62 import org.yaml.snakeyaml.Yaml;
63 import org.yaml.snakeyaml.constructor.AbstractConstruct;
64 import org.yaml.snakeyaml.constructor.Constructor;
65 import org.yaml.snakeyaml.nodes.ScalarNode;
66 import org.yaml.snakeyaml.nodes.Tag;
67
68
69
70
71 public class JcrImportCommand extends BaseRepositoryCommand {
72
73 private boolean saveAfterImport = true;
74 private int identifierBehavior = ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW;
75 private String fileName;
76 private String importPath;
77 private InputStream stream;
78
79 @Override
80 public boolean execute(Context context) throws Exception {
81 try {
82 final Node node = context.getJCRSession(getRepository()).getNode(getPath());
83 final String extension = FilenameUtils.getExtension(getFileName());
84 if (StringUtils.equalsIgnoreCase(JcrExportCommand.Format.YAML.name(), extension)) {
85 final ValueFactory valueFactory = node.getSession().getValueFactory();
86 final InputStreamReader inputStream = new InputStreamReader(getStream());
87 final Yaml yaml = new Yaml(new JcrPropertySupportingConstructor(valueFactory));
88 Map content = (Map) yaml.load(inputStream);
89 if (getImportPath() != null) {
90 final String[] path = StringUtils.split(getImportPath(), "/");
91 for (String nodeName : path) {
92 content = (Map) content.get(nodeName);
93 }
94 final Map<String, Object> wrappedTarget = new HashMap<>();
95 wrappedTarget.put(path[path.length - 1], content);
96 content = wrappedTarget;
97 }
98 yaml2Jcr(node, content);
99 if (isSaveAfterImport()) {
100 node.getSession().save();
101 }
102 } else {
103 final InputStream stream = importPath == null ? getStream() : BootstrapFileUtil.getElementAsStream(fileName, importPath);
104 DataTransporter.importXmlStream(stream, node.getSession().getWorkspace().getName(), node.getPath(), getFileName(), false, false, getIdentifierBehavior(), isSaveAfterImport(), true);
105 }
106 } finally {
107 if (stream != null) {
108 stream.close();
109 }
110 }
111 return true;
112 }
113
114 private void yaml2Jcr(Node root, Map<?, ?> map) throws RepositoryException {
115 for (Map.Entry entry : map.entrySet()) {
116 String key = String.valueOf(entry.getKey());
117 String nodeType = NodeTypes.ContentNode.NAME;
118 if (entry.getValue() == null || entry.getValue() instanceof Map) {
119 Map subMap = (Map) entry.getValue();
120 if (subMap == null) {
121 root.addNode(key, nodeType);
122 } else {
123 if (subMap.get(JcrConstants.JCR_PRIMARYTYPE) != null) {
124 nodeType = (String) subMap.get(JcrConstants.JCR_PRIMARYTYPE);
125 }
126 Node node;
127 if (subMap.get(JcrConstants.JCR_UUID) != null && NodeUtil.unwrap(root) instanceof NodeImpl) {
128 final Node unwrapped = NodeUtil.unwrap(root);
129 node = ((NodeImpl) unwrapped).addNodeWithUuid(key, nodeType, String.valueOf(subMap.get(JcrConstants.JCR_UUID)));
130 } else {
131 node = root.addNode(key, nodeType);
132 }
133 final Object mixins = subMap.get(JcrConstants.JCR_MIXINTYPES);
134 if (mixins instanceof Collection) {
135 for (Object mixin : (Collection) mixins) {
136 node.addMixin(String.valueOf(mixin));
137 }
138 }
139 yaml2Jcr(node, (Map) entry.getValue());
140 }
141 } else if (!Arrays.asList(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.JCR_UUID, JcrConstants.JCR_MIXINTYPES).contains(key)) {
142 PropertyUtil.setProperty(root, key, entry.getValue());
143 }
144 }
145 }
146
147 public boolean isSaveAfterImport() {
148 return saveAfterImport;
149 }
150
151 public void setSaveAfterImport(boolean saveAfterImport) {
152 this.saveAfterImport = saveAfterImport;
153 }
154
155 public int getIdentifierBehavior() {
156 return identifierBehavior;
157 }
158
159 public void setIdentifierBehavior(int identifierBehavior) {
160 this.identifierBehavior = identifierBehavior;
161 }
162
163 public String getFileName() {
164 return fileName;
165 }
166
167 public void setFileName(String fileName) {
168 this.fileName = fileName;
169 }
170
171 public String getImportPath() {
172 return importPath;
173 }
174
175 public void setImportPath(String subPathToImport) {
176 this.importPath = subPathToImport;
177 }
178
179 public InputStream getStream() {
180 return stream;
181 }
182
183 public void setStream(InputStream stream) {
184 this.stream = stream;
185 }
186
187 private static class JcrPropertySupportingConstructor extends Constructor {
188
189 private JcrPropertySupportingConstructor(ValueFactory valueFactory) {
190 yamlConstructors.put(new Tag("!" + StringUtils.lowerCase(PropertyType.TYPENAME_PATH)), new JcrConstruct(PropertyType.PATH, valueFactory));
191 yamlConstructors.put(new Tag("!" + StringUtils.lowerCase(PropertyType.TYPENAME_URI)), new JcrConstruct(PropertyType.URI, valueFactory));
192 yamlConstructors.put(new Tag("!" + StringUtils.lowerCase(PropertyType.TYPENAME_REFERENCE)), new JcrConstruct(PropertyType.REFERENCE, valueFactory));
193 yamlConstructors.put(new Tag("!" + StringUtils.lowerCase(PropertyType.TYPENAME_WEAKREFERENCE)), new JcrConstruct(PropertyType.WEAKREFERENCE, valueFactory));
194 yamlConstructors.put(new Tag("!" + StringUtils.lowerCase(PropertyType.TYPENAME_BINARY)), new JcrConstruct(PropertyType.BINARY, valueFactory));
195 }
196 }
197
198 private static class JcrConstruct extends AbstractConstruct {
199 private final int propertyType;
200 private final ValueFactory valueFactory;
201
202 private JcrConstruct(int propertyType, ValueFactory valueFactory) {
203 this.propertyType = propertyType;
204 this.valueFactory = valueFactory;
205 }
206
207 @Override
208 public Object construct(org.yaml.snakeyaml.nodes.Node node) {
209 try {
210 return ValueHelper.deserialize(((ScalarNode) node).getValue(), propertyType, false, valueFactory);
211 } catch (RepositoryException e) {
212 log.error(e.getMessage(), e);
213 return null;
214 }
215 }
216 }
217
218 }