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