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.postprocessors;
35
36 import java.util.ArrayList;
37 import java.util.HashMap;
38 import java.util.Map;
39 import javax.jcr.Node;
40 import javax.jcr.NodeIterator;
41 import javax.jcr.Property;
42 import javax.jcr.PropertyIterator;
43 import javax.jcr.RepositoryException;
44
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 import info.magnolia.cms.core.MetaData;
49 import info.magnolia.cms.core.MgnlNodeType;
50 import info.magnolia.jcr.util.NodeTypes;
51 import info.magnolia.jcr.util.NodeUtil;
52
53
54
55
56
57
58
59
60 public class MetaDataAsMixinConversionHelper {
61
62 private static final int PERIODIC_SAVE_FREQUENCY = 20;
63 private static final String DEPRECATED_DELETION_DATE_PROPERTY_NAME = "mgnl:deletedOn";
64
65 private final Logger logger = LoggerFactory.getLogger(MetaDataAsMixinConversionHelper.class);
66
67 private final HashMap<String, String> propertyNameMapping = new HashMap<String, String>();
68
69 private boolean deleteMetaDataIfEmptied = false;
70 private boolean periodicSaves = false;
71
72 public MetaDataAsMixinConversionHelper() {
73 propertyNameMapping.put(NodeTypes.MGNL_PREFIX + MetaData.CREATION_DATE, NodeTypes.Created.CREATED);
74 propertyNameMapping.put(NodeTypes.MGNL_PREFIX + MetaData.LAST_ACTION, NodeTypes.Activatable.LAST_ACTIVATED);
75 propertyNameMapping.put(NodeTypes.MGNL_PREFIX + MetaData.ACTIVATOR_ID, NodeTypes.Activatable.LAST_ACTIVATED_BY);
76 propertyNameMapping.put(NodeTypes.MGNL_PREFIX + MetaData.ACTIVATED, NodeTypes.Activatable.ACTIVATION_STATUS);
77 propertyNameMapping.put(NodeTypes.MGNL_PREFIX + MetaData.TEMPLATE, NodeTypes.Renderable.TEMPLATE);
78 propertyNameMapping.put(NodeTypes.MGNL_PREFIX + MetaData.LAST_MODIFIED, NodeTypes.LastModified.LAST_MODIFIED);
79 propertyNameMapping.put(NodeTypes.MGNL_PREFIX + MetaData.AUTHOR_ID, NodeTypes.LastModified.LAST_MODIFIED_BY);
80 propertyNameMapping.put("mgnl:comment", NodeTypes.Versionable.COMMENT);
81 }
82
83 public boolean isDeleteMetaDataIfEmptied() {
84 return deleteMetaDataIfEmptied;
85 }
86
87 public void setDeleteMetaDataIfEmptied(boolean deleteMetaDataIfEmptied) {
88 this.deleteMetaDataIfEmptied = deleteMetaDataIfEmptied;
89 }
90
91 public boolean isPeriodicSaves() {
92 return periodicSaves;
93 }
94
95
96
97
98 public void setPeriodicSaves(boolean periodicSaves) {
99 this.periodicSaves = periodicSaves;
100 }
101
102 public void convertNodeAndChildren(Node startNode) throws RepositoryException {
103
104 int nodesProcessed = 0;
105 ArrayList<Node> nodes = new ArrayList<Node>();
106 nodes.add(startNode);
107
108 while (!nodes.isEmpty()) {
109
110
111 Node node = nodes.remove(nodes.size() - 1);
112
113 processNode(node);
114
115
116 nodesProcessed++;
117 if (periodicSaves && nodesProcessed % PERIODIC_SAVE_FREQUENCY == 0) {
118 node.getSession().save();
119 }
120
121
122 NodeIterator children = node.getNodes();
123 while (children.hasNext()) {
124 Node child = children.nextNode();
125 if (!(child.getName().equals(MetaData.DEFAULT_META_NODE) && NodeUtil.isNodeType(child, MgnlNodeType.NT_METADATA))) {
126 nodes.add(child);
127 }
128 }
129 }
130 }
131
132 private void processNode(Node node) throws RepositoryException {
133
134
135 if (node.hasProperty(DEPRECATED_DELETION_DATE_PROPERTY_NAME)) {
136 moveProperty(node, DEPRECATED_DELETION_DATE_PROPERTY_NAME, node, NodeTypes.Deleted.DELETED);
137 }
138
139
140 if (node.hasNode(MetaData.DEFAULT_META_NODE)) {
141 Node metaDataNode = node.getNode(MetaData.DEFAULT_META_NODE);
142 if (NodeUtil.isNodeType(metaDataNode, MgnlNodeType.NT_METADATA)) {
143 moveProperties(node, metaDataNode, propertyNameMapping);
144 }
145
146 if (deleteMetaDataIfEmptied && isEmptyMetaDataNode(metaDataNode)) {
147 metaDataNode.remove();
148 }
149 }
150 }
151
152
153
154
155 private boolean isEmptyMetaDataNode(Node node) throws RepositoryException {
156 if (node.getNodes().getSize() != 0) {
157 logger.warn("MetaData node not removed because it has sub nodes " + node.getPath());
158 return false;
159 }
160 PropertyIterator iterator = node.getProperties();
161 while (iterator.hasNext()) {
162 Property property = iterator.nextProperty();
163 if (!isExpectedMetaDataProperty(property)) {
164 logger.warn("MetaData node not removed because of unrecognized property: " + property.getPath());
165 return false;
166 }
167 }
168 return true;
169 }
170
171
172
173
174 private boolean isExpectedMetaDataProperty(Property property) throws RepositoryException {
175 String propertyName = property.getName();
176
177
178 if (propertyName.startsWith("jcr:")) {
179 return true;
180 }
181
182
183 if (propertyName.equals(NodeTypes.MGNL_PREFIX + MetaData.TITLE) || propertyName.equals(NodeTypes.MGNL_PREFIX + MetaData.TEMPLATE_TYPE)) {
184 return true;
185 }
186
187
188 if (propertyName.equals(NodeTypes.MGNL_PREFIX + "Data") && property.getString().equals("MetaData")) {
189 return true;
190 }
191
192 return false;
193 }
194
195
196
197
198
199
200
201
202
203 private void moveProperties(Node dstNode, Node srcNode, Map<String, String> nameMappings) throws RepositoryException {
204 for (Map.Entry<String, String> entry : nameMappings.entrySet()) {
205 String srcPropertyName = entry.getKey();
206 String dstPropertyName = entry.getValue();
207 if (!dstNode.hasProperty(dstPropertyName) && srcNode.hasProperty(srcPropertyName)) {
208 moveProperty(srcNode, srcPropertyName, dstNode, dstPropertyName);
209 }
210 }
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224
225 private void moveProperty(Node srcNode, String srcPropertyName, Node dstNode, String dstPropertyName) throws RepositoryException {
226 Property srcProperty = srcNode.getProperty(srcPropertyName);
227 if (srcProperty.isMultiple()) {
228 dstNode.setProperty(dstPropertyName, srcProperty.getValues());
229 } else {
230 dstNode.setProperty(dstPropertyName, srcProperty.getValue());
231 }
232 srcProperty.remove();
233 }
234 }