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 import org.apache.commons.beanutils.ConvertUtils;
43 import org.apache.commons.lang.StringUtils;
44 import org.apache.jackrabbit.util.ISO8601;
45
46 import javax.jcr.PropertyType;
47 import javax.jcr.RepositoryException;
48 import javax.jcr.Value;
49
50 import java.io.ByteArrayInputStream;
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.util.Calendar;
54 import java.util.Collection;
55 import java.util.Properties;
56 import java.util.Set;
57
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
236 private static Properties toProperties(Content rootContent, Content.ContentFilter contentFilter, final boolean legacyMode) throws Exception {
237 final Properties out = new OrderedProperties();
238 ContentUtil.visit(rootContent, new ContentUtil.Visitor() {
239 @Override
240 public void visit(Content node) throws Exception {
241 if (!legacyMode) {
242 appendNodeTypeAndUUID(node, out, true);
243 }
244 appendNodeProperties(node, out);
245 }
246 }, contentFilter);
247 return out;
248 }
249
250 private static void appendNodeTypeAndUUID(Content node, Properties out, final boolean dumpMetaData) throws RepositoryException {
251 String path = getExportPath(node);
252
253 if (path.equals("/jcr:root")) {
254 return;
255 }
256
257 String nodeTypeName = node.getNodeTypeName();
258 if (nodeTypeName != null && StringUtils.isNotEmpty(nodeTypeName)) {
259 out.put(path + "@type", nodeTypeName);
260 }
261 String nodeUUID = node.getUUID();
262 if (nodeUUID != null && StringUtils.isNotEmpty(nodeUUID)) {
263 out.put(path + "@uuid", node.getUUID());
264 }
265 }
266
267 public static void appendNodeProperties(Content node, Properties out) {
268 final Collection<NodeData> props = node.getNodeDataCollection();
269 for (NodeData prop : props) {
270 final String path = getExportPath(node) + "." + prop.getName();
271
272 String propertyValue = getPropertyString(prop);
273
274 if (propertyValue != null) {
275 out.setProperty(path, propertyValue);
276 }
277 }
278 }
279
280 private static String getExportPath(Content node) {
281 return node.getHandle();
282 }
283
284 private static String getPropertyString(NodeData prop) {
285 int propType = prop.getType();
286
287 switch (propType) {
288 case (PropertyType.STRING): {
289 return prop.getString();
290 }
291 case (PropertyType.BOOLEAN): {
292 return convertBooleanToExportString(prop.getBoolean());
293 }
294 case (PropertyType.BINARY): {
295 return convertBinaryToExportString(prop.getValue());
296 }
297 case (PropertyType.PATH): {
298 return prop.getString();
299 }
300 case (PropertyType.DATE): {
301 return convertCalendarToExportString(prop.getDate());
302 }
303 case (PropertyType.LONG): {
304 return "" + prop.getLong();
305 }
306 case (PropertyType.DOUBLE): {
307 return "" + prop.getDouble();
308 }
309 default: {
310 return prop.getString();
311 }
312 }
313 }
314
315 private static String convertBooleanToExportString(boolean b) {
316 return "boolean:" + (b ? "true" : "false");
317 }
318
319 private static String convertBinaryToExportString(Value value) {
320 return "binary:" + ConvertUtils.convert(value);
321 }
322
323 private static String convertCalendarToExportString(Calendar calendar) {
324 return "date:" + ISO8601.format(calendar);
325 }
326
327
328
329
330
331 public static String dumpPropertiesToString(Content content, Content.ContentFilter filter) throws Exception {
332 Properties properties = PropertiesImportExport.contentToProperties(content, filter);
333 return dumpPropertiesToString(properties);
334 }
335
336 public static String dumpPropertiesToString(Properties properties) {
337 final StringBuilder sb = new StringBuilder();
338 final Set<Object> propertyNames = properties.keySet();
339 for (Object propertyKey : propertyNames) {
340 final String name = propertyKey.toString();
341 final String value = properties.getProperty(name);
342 sb.append(name);
343 sb.append("=");
344 sb.append(value);
345 sb.append("\n");
346 }
347 return sb.toString();
348 }
349
350 private static boolean contains(String s, char ch) {
351 return s.indexOf(ch) > -1;
352 }
353 }