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.module.exchangesimple;
35
36 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.ACTION;
37 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.ACTIVATE;
38 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.CONTENT_FILTER_RULE;
39 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.NODE_UUID;
40 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.PARENT_PATH;
41 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.REPOSITORY_NAME;
42 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.RESOURCE_MAPPING_FILE;
43 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.RESOURCE_MAPPING_FILE_ELEMENT;
44 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.RESOURCE_MAPPING_ID_ATTRIBUTE;
45 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.RESOURCE_MAPPING_MD_ATTRIBUTE;
46 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.RESOURCE_MAPPING_NAME_ATTRIBUTE;
47 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.RESOURCE_MAPPING_ROOT_ELEMENT;
48 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.RESOURCE_MAPPING_UUID_ATTRIBUTE;
49 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.SIBLINGS_ELEMENT;
50 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.SIBLINGS_ROOT_ELEMENT;
51 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.SIBLING_UUID;
52 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.UTF8_STATUS;
53 import static info.magnolia.module.exchangesimple.BaseSyndicatorImpl.WORKSPACE_NAME;
54 import info.magnolia.cms.core.Content;
55 import info.magnolia.cms.core.ItemType;
56 import info.magnolia.cms.core.Path;
57 import info.magnolia.cms.core.SystemProperty;
58 import info.magnolia.cms.security.SecurityUtil;
59 import info.magnolia.cms.util.Rule;
60 import info.magnolia.cms.util.RuleBasedContentFilter;
61 import info.magnolia.jcr.wrapper.DelegateNodeWrapper;
62 import info.magnolia.repository.RepositoryConstants;
63
64 import java.io.ByteArrayOutputStream;
65 import java.io.File;
66 import java.io.FileInputStream;
67 import java.io.FileOutputStream;
68 import java.io.IOException;
69 import java.io.OutputStream;
70 import java.util.Iterator;
71 import java.util.List;
72 import java.util.zip.GZIPOutputStream;
73
74 import javax.jcr.Node;
75 import javax.jcr.RepositoryException;
76 import javax.jcr.Session;
77
78 import org.apache.commons.io.IOUtils;
79 import org.apache.commons.io.output.TeeOutputStream;
80 import org.apache.xml.serialize.OutputFormat;
81 import org.apache.xml.serialize.XMLSerializer;
82 import org.jdom.Document;
83 import org.jdom.Element;
84 import org.jdom.output.XMLOutputter;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
87 import org.xml.sax.InputSource;
88 import org.xml.sax.SAXException;
89 import org.xml.sax.XMLReader;
90 import org.xml.sax.helpers.XMLReaderFactory;
91
92
93
94
95
96
97
98 public class ResourceCollector {
99 private static final Logger log = LoggerFactory.getLogger(ResourceCollector.class);
100
101
102
103
104
105
106
107
108
109
110
111 protected ActivationContent collect(Content node, List<String> orderBefore, String parent, String workspaceName, String repositoryName, Rule contentFilterRule) throws Exception {
112 Content.ContentFilter contentFilter = new RuleBasedContentFilter(contentFilterRule);
113
114
115 File resourceFile = File.createTempFile("resources", ".xml", Path.getTempDirectory());
116
117 ActivationContent activationContent = new ActivationContent();
118
119 activationContent.addProperty(PARENT_PATH, parent);
120 activationContent.addProperty(WORKSPACE_NAME, workspaceName);
121 activationContent.addProperty(REPOSITORY_NAME, repositoryName);
122 activationContent.addProperty(RESOURCE_MAPPING_FILE, resourceFile.getName());
123 activationContent.addProperty(ACTION, ACTIVATE);
124 activationContent.addProperty(CONTENT_FILTER_RULE, contentFilterRule.toString());
125 activationContent.addProperty(NODE_UUID, node.getUUID());
126 activationContent.addProperty(UTF8_STATUS, SystemProperty.getProperty(SystemProperty.MAGNOLIA_UTF8_ENABLED));
127
128 Document document = new Document();
129 Element root = new Element(RESOURCE_MAPPING_ROOT_ELEMENT);
130 document.setRootElement(root);
131
132 addOrderingInfo(root, orderBefore);
133
134 this.addResources(root, node.getWorkspace().getSession(), node, contentFilter, activationContent);
135 XMLOutputter outputter = new XMLOutputter();
136
137 ByteArrayOutputStream md5 = new ByteArrayOutputStream();
138 outputter.output(document, new TeeOutputStream(new FileOutputStream(resourceFile), md5));
139
140 activationContent.addFile(resourceFile.getName(), resourceFile);
141
142 activationContent.addProperty(RESOURCE_MAPPING_MD_ATTRIBUTE, SecurityUtil.getMD5Hex(md5.toByteArray()));
143
144
145 activationContent.addProperty(ItemType.DELETED_NODE_MIXIN, "" + node.hasMixin(ItemType.DELETED_NODE_MIXIN));
146
147 return activationContent;
148 }
149
150
151
152
153
154
155
156
157 protected void addOrderingInfo(Element root, List<String> orderBefore) {
158
159 Element siblingRoot = new Element(SIBLINGS_ROOT_ELEMENT);
160 root.addContent(siblingRoot);
161 if (orderBefore == null) {
162 return;
163 }
164 Iterator<String> siblings = orderBefore.iterator();
165 while (siblings.hasNext()) {
166 String uuid = siblings.next();
167 Element e = new Element(SIBLINGS_ELEMENT);
168 e.setAttribute(SIBLING_UUID, uuid);
169 siblingRoot.addContent(e);
170 }
171 }
172
173 protected void addResources(Element resourceElement, Session session, final Content content, Content.ContentFilter filter, ActivationContent activationContent) throws IOException, RepositoryException, SAXException, Exception {
174 final String workspaceName = content.getWorkspace().getName();
175
176 log.debug("Preparing content {}:{} for publishing.", new String[] { workspaceName, content.getHandle() });
177 final String uuid = content.getUUID();
178
179 File file = File.createTempFile("exchange_" + uuid, ".xml.gz", Path.getTempDirectory());
180
181 ByteArrayOutputStream md5 = new ByteArrayOutputStream();
182 OutputStream outputStream = new TeeOutputStream(new GZIPOutputStream(new FileOutputStream(file)), md5);
183
184
185 if (content.isNodeType("nt:frozenNode") || workspaceName.equals(RepositoryConstants.VERSION_STORE)) {
186 XMLReader elementfilter = new FrozenElementFilter(XMLReaderFactory
187 .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName()));
188 ((FrozenElementFilter) elementfilter).setNodeName(content.getName());
189
190
191
192 boolean noRecurse = !content.isNodeType(ItemType.NT_FILE);
193 exportAndParse(session, content, elementfilter, outputStream, noRecurse);
194 } else {
195
196
197
198 if (content.isNodeType(ItemType.NT_FILE)) {
199 session.exportSystemView(content.getJCRNode().getPath(), outputStream, false, false);
200 } else {
201 session.exportSystemView(content.getJCRNode().getPath(), outputStream, false, true);
202 }
203 }
204
205 IOUtils.closeQuietly(outputStream);
206
207 Element element = new Element(RESOURCE_MAPPING_FILE_ELEMENT);
208 element.setAttribute(RESOURCE_MAPPING_NAME_ATTRIBUTE, content.getName());
209 element.setAttribute(RESOURCE_MAPPING_UUID_ATTRIBUTE, uuid);
210 element.setAttribute(RESOURCE_MAPPING_ID_ATTRIBUTE, file.getName());
211
212 element.setAttribute(RESOURCE_MAPPING_MD_ATTRIBUTE, SecurityUtil.getMD5Hex(md5.toByteArray()));
213
214 resourceElement.addContent(element);
215
216 activationContent.addFile(file.getName(), file);
217
218 Iterator<Content> children = content.getChildren(filter).iterator();
219 while (children.hasNext()) {
220 Content child = children.next();
221 this.addResources(element, session, child, filter, activationContent);
222 }
223 }
224
225
226
227
228 protected void exportAndParse(Session session, Content content, XMLReader elementfilter, OutputStream os, boolean noRecurse) throws Exception {
229 File tempFile = File.createTempFile("Frozen_" + content.getName(), ".xml");
230 OutputStream tmpFileOutStream = null;
231 FileInputStream tmpFileInStream = null;
232 try {
233 tmpFileOutStream = new FileOutputStream(tempFile);
234
235 Node node = content.getJCRNode();
236 if (node instanceof DelegateNodeWrapper) {
237 node = ((DelegateNodeWrapper) node).getWrappedNode();
238 }
239 session.exportSystemView(node.getPath(), tmpFileOutStream, false, noRecurse);
240 tmpFileOutStream.flush();
241 tmpFileOutStream.close();
242
243 OutputFormat outputFormat = new OutputFormat();
244 outputFormat.setPreserveSpace(false);
245
246 tmpFileInStream = new FileInputStream(tempFile);
247 elementfilter.setContentHandler(new XMLSerializer(os, outputFormat));
248 elementfilter.parse(new InputSource(tmpFileInStream));
249 tmpFileInStream.close();
250 } catch (Throwable t) {
251 log.error("Failed to parse XML using FrozenElementFilter", t);
252 throw new Exception(t);
253 } finally {
254 IOUtils.closeQuietly(tmpFileInStream);
255 IOUtils.closeQuietly(tmpFileOutStream);
256 tempFile.delete();
257 }
258 }
259
260
261
262
263
264 }