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