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