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;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.HierarchyManager;
38 import info.magnolia.cms.core.ItemType;
39 import info.magnolia.cms.core.NodeData;
40 import info.magnolia.cms.util.ContentUtil;
41 import info.magnolia.cms.util.OrderedProperties;
42
43 import java.io.ByteArrayInputStream;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.util.Calendar;
47 import java.util.Collection;
48 import java.util.Properties;
49 import java.util.Set;
50
51 import javax.jcr.PropertyType;
52 import javax.jcr.RepositoryException;
53 import javax.jcr.Value;
54
55 import org.apache.commons.beanutils.ConvertUtils;
56 import org.apache.commons.lang3.StringUtils;
57 import org.apache.jackrabbit.util.ISO8601;
58
59
60
61
62
63
64
65
66
67
68 public class PropertiesImportExport {
69
70 public void createContent(Content root, InputStream propertiesStream) throws IOException, RepositoryException {
71 Properties properties = new OrderedProperties();
72
73 properties.load(propertiesStream);
74
75 properties = keysToInnerFormat(properties);
76
77 for (Object o : properties.keySet()) {
78 String key = (String) o;
79 String valueStr = properties.getProperty(key);
80
81 String propertyName = StringUtils.substringAfterLast(key, ".");
82 String path = StringUtils.substringBeforeLast(key, ".");
83
84 String type = null;
85 if (propertyName.equals("@type")) {
86 type = valueStr;
87 } else if (properties.containsKey(path + ".@type")) {
88 type = properties.getProperty(path + ".@type");
89 }
90
91 type = StringUtils.defaultIfEmpty(type, ItemType.CONTENTNODE.getSystemName());
92 Content c = ContentUtil.createPath(root, path, new ItemType(type));
93 populateContent(c, propertyName, valueStr);
94 }
95 }
96
97
98
99
100 private Properties keysToInnerFormat(Properties properties) {
101 Properties cleaned = new OrderedProperties();
102
103 for (Object o : properties.keySet()) {
104 String orgKey = (String) o;
105
106
107 String newKey = orgKey;
108
109
110 newKey = StringUtils.replace(newKey, "@", ".@");
111
112 newKey = StringUtils.replace(newKey, "..@", ".@");
113
114 String propertyName = StringUtils.substringAfterLast(newKey, ".");
115 String keySuffix = StringUtils.substringBeforeLast(newKey, ".");
116 String path = StringUtils.replace(keySuffix, ".", "/");
117 path = StringUtils.removeStart(path, "/");
118
119
120 if (StringUtils.isEmpty(propertyName)) {
121
122 if (StringUtils.isEmpty(properties.getProperty(orgKey))) {
123
124 if (!properties.containsKey(orgKey + "@type")) {
125 cleaned.put(path + ".@type", ItemType.CONTENTNODE.getSystemName());
126 }
127 continue;
128 }
129 propertyName = StringUtils.substringAfterLast(path, "/");
130 path = StringUtils.substringBeforeLast(path, "/");
131 }
132 cleaned.put(path + "." + propertyName, properties.get(orgKey));
133 }
134 return cleaned;
135 }
136
137 protected void populateContent(Content c, String name, String valueStr) throws RepositoryException {
138 if (StringUtils.isEmpty(name) && StringUtils.isEmpty(valueStr)) {
139
140 return;
141 }
142 if (name.equals("@type")) {
143
144 } else if (name.equals("@uuid")) {
145 throw new UnsupportedOperationException("Can't see UUIDs on real node. Use MockUtil if you are using MockContent instances.");
146 } else {
147 Object valueObj = convertNodeDataStringToObject(valueStr);
148 c.setNodeData(name, valueObj);
149 }
150 }
151
152 protected Object convertNodeDataStringToObject(String valueStr) {
153 if (contains(valueStr, ':')) {
154 final String type = StringUtils.substringBefore(valueStr, ":");
155 final String value = StringUtils.substringAfter(valueStr, ":");
156
157
158 if (type.equalsIgnoreCase("date")) {
159 return ISO8601.parse(value);
160 } else if (type.equalsIgnoreCase("binary")) {
161 return new ByteArrayInputStream(value.getBytes());
162 } else {
163 try {
164 final Class<?> typeCl;
165 if (type.equals("int")) {
166 typeCl = Integer.class;
167 } else {
168 typeCl = Class.forName("java.lang." + StringUtils.capitalize(type));
169 }
170 return ConvertUtils.convert(value, typeCl);
171 } catch (ClassNotFoundException e) {
172
173 return valueStr;
174 }
175 }
176 }
177
178 return valueStr;
179 }
180
181
182
183
184
185
186
187
188
189
190
191 @Deprecated
192 public static Properties toProperties(HierarchyManager hm) throws Exception {
193 return toProperties(hm.getRoot());
194 }
195
196
197
198
199 public static Properties toProperties(Content rootContent) throws Exception {
200 return toProperties(rootContent, ContentUtil.EXCLUDE_META_DATA_CONTENT_FILTER, true);
201 }
202
203
204
205
206 public static Properties contentToProperties(HierarchyManager hm) throws Exception {
207 return contentToProperties(hm.getRoot());
208 }
209
210
211
212
213 public static Properties contentToProperties(Content rootContent) throws Exception {
214 return toProperties(rootContent, ContentUtil.EXCLUDE_META_DATA_CONTENT_FILTER, false);
215 }
216
217
218
219
220 public static Properties contentToProperties(Content rootContent, Content.ContentFilter filter) throws Exception {
221 return toProperties(rootContent, filter, false);
222 }
223
224
225
226
227
228
229
230
231
232
233
234
235 private static Properties toProperties(Content rootContent, Content.ContentFilter contentFilter, final boolean legacyMode) throws Exception {
236 final Properties out = new OrderedProperties();
237 ContentUtil.visit(rootContent, new ContentUtil.Visitor() {
238 @Override
239 public void visit(Content node) throws Exception {
240 if (!legacyMode) {
241 appendNodeTypeAndUUID(node, out, true);
242 }
243 appendNodeProperties(node, out);
244 }
245 }, contentFilter);
246 return out;
247 }
248
249 private static void appendNodeTypeAndUUID(Content node, Properties out, final boolean dumpMetaData) throws RepositoryException {
250 String path = getExportPath(node);
251
252 if (path.equals("/jcr:root")) {
253 return;
254 }
255
256 String nodeTypeName = node.getNodeTypeName();
257 if (nodeTypeName != null && StringUtils.isNotEmpty(nodeTypeName)) {
258 out.put(path + "@type", nodeTypeName);
259 }
260 String nodeUUID = node.getUUID();
261 if (nodeUUID != null && StringUtils.isNotEmpty(nodeUUID)) {
262 out.put(path + "@uuid", node.getUUID());
263 }
264 }
265
266 public static void appendNodeProperties(Content node, Properties out) {
267 final Collection<NodeData> props = node.getNodeDataCollection();
268 for (NodeData prop : props) {
269 final String path = getExportPath(node) + "." + prop.getName();
270
271 String propertyValue = getPropertyString(prop);
272
273 if (propertyValue != null) {
274 out.setProperty(path, propertyValue);
275 }
276 }
277 }
278
279 private static String getExportPath(Content node) {
280 return node.getHandle();
281 }
282
283 private static String getPropertyString(NodeData prop) {
284 int propType = prop.getType();
285
286 switch (propType) {
287 case (PropertyType.STRING): {
288 return prop.getString();
289 }
290 case (PropertyType.BOOLEAN): {
291 return convertBooleanToExportString(prop.getBoolean());
292 }
293 case (PropertyType.BINARY): {
294 return convertBinaryToExportString(prop.getValue());
295 }
296 case (PropertyType.PATH): {
297 return prop.getString();
298 }
299 case (PropertyType.DATE): {
300 return convertCalendarToExportString(prop.getDate());
301 }
302 case (PropertyType.LONG): {
303 return "" + prop.getLong();
304 }
305 case (PropertyType.DOUBLE): {
306 return "" + prop.getDouble();
307 }
308 default: {
309 return prop.getString();
310 }
311 }
312 }
313
314 private static String convertBooleanToExportString(boolean b) {
315 return "boolean:" + (b ? "true" : "false");
316 }
317
318 private static String convertBinaryToExportString(Value value) {
319 return "binary:" + ConvertUtils.convert(value);
320 }
321
322 private static String convertCalendarToExportString(Calendar calendar) {
323 return "date:" + ISO8601.format(calendar);
324 }
325
326
327
328
329
330 public static String dumpPropertiesToString(Content content, Content.ContentFilter filter) throws Exception {
331 Properties properties = PropertiesImportExport.contentToProperties(content, filter);
332 return dumpPropertiesToString(properties);
333 }
334
335 public static String dumpPropertiesToString(Properties properties) {
336 final StringBuilder sb = new StringBuilder();
337 final Set<Object> propertyNames = properties.keySet();
338 for (Object propertyKey : propertyNames) {
339 final String name = propertyKey.toString();
340 final String value = properties.getProperty(name);
341 sb.append(name);
342 sb.append("=");
343 sb.append(value);
344 sb.append("\n");
345 }
346 return sb.toString();
347 }
348
349 private static boolean contains(String s, char ch) {
350 return s.indexOf(ch) > -1;
351 }
352 }