KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > info > magnolia > cms > exchange > simple > BaseSyndicatorImpl


1 /**
2  *
3  * Magnolia and its source-code is licensed under the LGPL.
4  * You may copy, adapt, and redistribute this file for commercial or non-commercial use.
5  * When copying, adapting, or redistributing this document in keeping with the guidelines above,
6  * you are required to provide proper attribution to obinary.
7  * If you reproduce or distribute the document without making any substantive modifications to its content,
8  * please use the following attribution line:
9  *
10  * Copyright 1993-2005 obinary Ltd. (http://www.obinary.com) All rights reserved.
11  *
12  */

13 package info.magnolia.cms.exchange.simple;
14
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17 import org.apache.commons.codec.binary.Base64;
18 import org.apache.commons.io.IOUtils;
19 import org.apache.xml.serialize.OutputFormat;
20 import org.apache.xml.serialize.XMLSerializer;
21 import org.jdom.Document;
22 import org.jdom.Element;
23 import org.jdom.output.XMLOutputter;
24 import org.xml.sax.SAXException JavaDoc;
25 import org.xml.sax.XMLReader JavaDoc;
26 import org.xml.sax.InputSource JavaDoc;
27 import org.xml.sax.helpers.XMLReaderFactory JavaDoc;
28 import info.magnolia.cms.core.*;
29 import info.magnolia.cms.util.ContentUtil;
30 import info.magnolia.cms.util.Rule;
31 import info.magnolia.cms.util.RuleBasedContentFilter;
32 import info.magnolia.cms.security.User;
33 import info.magnolia.cms.security.AccessDeniedException;
34 import info.magnolia.cms.exchange.ExchangeException;
35 import info.magnolia.cms.exchange.ActivationContent;
36 import info.magnolia.cms.exchange.Syndicator;
37 import info.magnolia.cms.beans.config.Subscriber;
38 import info.magnolia.cms.beans.config.ContentRepository;
39 import info.magnolia.context.MgnlContext;
40
41 import javax.jcr.RepositoryException;
42 import javax.jcr.Session;
43 import java.util.List JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.zip.GZIPOutputStream JavaDoc;
46 import java.net.URLConnection JavaDoc;
47 import java.io.*;
48
49 /**
50  * @author Sameer Charles
51  * $Id$
52  */

53 public abstract class BaseSyndicatorImpl implements Syndicator {
54
55     /**
56       * activation handler servlet name as mapped in web descriptor
57       */

58      public static final String JavaDoc DEFAULT_HANDLER = "ActivationHandler"; //$NON-NLS-1$
59

60      /**
61       * parent path
62       */

63      public static final String JavaDoc PARENT_PATH = "mgnlExchangeParentPath";
64
65      /**
66       * activated/deactivated path
67       */

68      public static final String JavaDoc PATH = "mgnlExchangePath";
69
70      /**
71       * repository name
72       */

73      public static final String JavaDoc REPOSITORY_NAME = "mgnlExchangeRepositoryName";
74
75      /**
76       * workspace name
77       */

78      public static final String JavaDoc WORKSPACE_NAME = "mgnlExchangeWorkspaceName";
79
80      /**
81       * resource reading sequence
82       */

83      public static final String JavaDoc RESOURCE_MAPPING_FILE = "mgnlExchangeResourceMappingFile";
84
85      /**
86       * resource file, Siblings element
87       * siblings element will contain all siglings of the same node type which are "before"
88       * this node
89       */

90      public static final String JavaDoc SIBLINGS_ROOT_ELEMENT = "NodeSiblings";
91
92      /**
93       * sibling
94       * */

95      public static final String JavaDoc SIBLINGS_ELEMENT = "sibling";
96
97      /**
98       * sibling UUID
99       * */

100      public static final String JavaDoc SIBLING_UUID = "UUID";
101
102      /**
103       * resource file, File element
104       */

105      public static final String JavaDoc RESOURCE_MAPPING_FILE_ELEMENT = "File";
106
107      /**
108       * resource file, name attribute
109       */

110      public static final String JavaDoc RESOURCE_MAPPING_NAME_ATTRIBUTE = "name";
111
112      /**
113       * resource file, name attribute
114       */

115      public static final String JavaDoc RESOURCE_MAPPING_UUID_ATTRIBUTE = "contentUUID";
116
117      /**
118       * resource file, resourceId attribute
119       */

120      public static final String JavaDoc RESOURCE_MAPPING_ID_ATTRIBUTE = "resourceId";
121
122      /**
123       * resource file, root element
124       */

125      public static final String JavaDoc RESOURCE_MAPPING_ROOT_ELEMENT = "Resources";
126
127      /**
128       * Action
129       */

130      public static final String JavaDoc ACTION = "mgnlExchangeAction";
131
132      /**
133       * possible value for attribute "ACTION"
134       */

135      public static final String JavaDoc ACTIVATE = "activate"; //$NON-NLS-1$
136

137      /**
138       * possible value for attribute "ACTION"
139       */

140      public static final String JavaDoc DE_ACTIVATE = "deactivate"; //$NON-NLS-1$
141

142      /**
143       * request authorization exception
144       */

145      public static final String JavaDoc AUTHORIZATION = "Authorization";
146
147      /**
148       * attribute rule
149       */

150      public static final String JavaDoc CONTENT_FILTER_RULE = "mgnlExchangeFilterRule";
151
152      /**
153       * return status values all simple activation headers start from sa_
154       */

155      public static final String JavaDoc ACTIVATION_SUCCESSFUL = "sa_success"; //$NON-NLS-1$
156

157      public static final String JavaDoc ACTIVATION_FAILED = "sa_failed"; //$NON-NLS-1$
158

159      public static final String JavaDoc ACTIVATION_ATTRIBUTE_STATUS = "sa_attribute_status"; //$NON-NLS-1$
160

161      public static final String JavaDoc ACTIVATION_ATTRIBUTE_MESSAGE = "sa_attribute_message"; //$NON-NLS-1$
162

163      /**
164       * Logger.
165       */

166      private static Logger log = LoggerFactory.getLogger(SimpleSyndicator.class);
167
168      protected String JavaDoc repositoryName;
169
170      protected String JavaDoc workspaceName;
171
172      protected String JavaDoc parent;
173
174      protected String JavaDoc path;
175
176      protected Content.ContentFilter contentFilter;
177
178      protected Rule contentFilterRule;
179
180      protected User user;
181
182      protected String JavaDoc basicCredentials;
183
184      /**
185       * @param user
186       * @param repositoryName repository ID
187       * @param workspaceName workspace ID
188       * @param rule content filter rule
189       * @see info.magnolia.cms.exchange.Syndicator#init(info.magnolia.cms.security.User, String, String,
190       * info.magnolia.cms.util.Rule)
191       */

192      public void init(User user, String JavaDoc repositoryName, String JavaDoc workspaceName, Rule rule) {
193          this.user = user;
194          this.basicCredentials = "Basic "
195              + new String JavaDoc(Base64.encodeBase64((this.user.getName() + ":" + this.user.getPassword()).getBytes()));
196          this.contentFilter = new RuleBasedContentFilter(rule);
197          this.contentFilterRule = rule;
198          this.repositoryName = repositoryName;
199          this.workspaceName = workspaceName;
200      }
201
202      /**
203       * <p/> this will activate specifies page (sub pages) to all configured subscribers
204       * </p>
205       * @param parent parent under which this page will be activated
206       * @param path page to be activated
207       * @throws javax.jcr.RepositoryException
208       * @throws info.magnolia.cms.exchange.ExchangeException
209       */

210      public synchronized void activate(String JavaDoc parent, String JavaDoc path) throws ExchangeException, RepositoryException {
211          log.info("Method activate(String, String) is deprecated, use Syndicator#activate(String, info.magnolia.cms.core.Content)");
212          HierarchyManager hm = MgnlContext.getHierarchyManager(this.repositoryName, this.workspaceName);
213          this.activate(parent, hm.getContent(path));
214      }
215
216      /**
217       * <p/> this will activate specifies page (sub pages) to all configured subscribers
218       * </p>
219       * @param parent parent under which this page will be activated
220       * @param content to be activated
221       * @throws javax.jcr.RepositoryException
222       * @throws info.magnolia.cms.exchange.ExchangeException
223       */

224      public void activate(String JavaDoc parent, Content content) throws ExchangeException, RepositoryException {
225          this.activate(parent, content, null);
226      }
227
228      /**
229       * <p/>
230       * this will activate specified node to all configured subscribers
231       * </p>
232       *
233       * @param parent parent under which this page will be activated
234       * @param content to be activated
235       * @param orderBefore List of UUID to be used by the implementation to order this node after activation
236       * @throws javax.jcr.RepositoryException
237       * @throws info.magnolia.cms.exchange.ExchangeException
238       *
239       */

240      public void activate(String JavaDoc parent, Content content, List JavaDoc orderBefore)
241              throws ExchangeException, RepositoryException {
242          this.parent = parent;
243          this.path = content.getHandle();
244          ActivationContent activationContent = null;
245          try {
246              activationContent = this.collect(content, orderBefore);
247              this.activate(activationContent);
248              this.updateActivationDetails();
249              log.info("Exchange: activation succeeded [{}]", content.getHandle());
250          }
251          catch (Exception JavaDoc e) {
252              if (log.isDebugEnabled()) {
253                  log.error("Excahnge: activation failed for path:" + ((path != null) ? path : "[null]"), e);
254              }
255              throw new ExchangeException(e);
256          }
257          finally {
258              if (log.isDebugEnabled()) {
259                  log.debug("Cleaning temporary files");
260              }
261              cleanTemporaryStore(activationContent);
262          }
263      }
264
265      /**
266       * <p/> this will activate specifies page (sub pages) to the specified subscribers
267       * </p>
268       * @param subscriber
269       * @param parent parent under which this page will be activated
270       * @param content to be activated
271       * @throws javax.jcr.RepositoryException
272       * @throws info.magnolia.cms.exchange.ExchangeException
273       */

274      public void activate(Subscriber subscriber, String JavaDoc parent, Content content)
275              throws ExchangeException, RepositoryException {
276          throw new ExchangeException("Not implemented");
277      }
278
279      /**
280       * <p/>
281       * this will activate specifies node to the specified subscribers
282       * </p>
283       *
284       * @param subscriber
285       * @param parent parent under which this page will be activated
286       * @param content to be activated
287       * @param orderBefore List of UUID to be used by the subscriber to order this node after activation
288       * @throws javax.jcr.RepositoryException
289       * @throws info.magnolia.cms.exchange.ExchangeException
290       *
291       */

292      public void activate(Subscriber subscriber, String JavaDoc parent, Content content, List JavaDoc orderBefore)
293              throws ExchangeException, RepositoryException {
294          throw new ExchangeException("Not implemented");
295      }
296
297      /**
298       * @throws ExchangeException
299       */

300      public abstract void activate(ActivationContent activationContent) throws ExchangeException;
301
302
303      /**
304       * Send activation request if subscribed to the activated URI
305       * @param subscriber
306       * @param activationContent
307       * @throws ExchangeException
308       */

309      public abstract void activate(Subscriber subscriber, ActivationContent activationContent)
310          throws ExchangeException;
311
312      /**
313       * cleans temporary store
314       * @param activationContent
315       */

316      protected void cleanTemporaryStore(ActivationContent activationContent) {
317          if (activationContent == null) {
318              if (log.isDebugEnabled()) {
319                  log.debug("Clean temporary store - nothing to do");
320              }
321              return;
322          }
323          Iterator JavaDoc keys = activationContent.getFiles().keySet().iterator();
324          while (keys.hasNext()) {
325              String JavaDoc key = (String JavaDoc) keys.next();
326              if (log.isDebugEnabled()) {
327                  log.debug("Removing temporary file {}", key);
328              }
329              activationContent.getFile(key).delete();
330          }
331      }
332
333      /**
334       * Check if this subscriber is subscribed to this uri
335       * @param subscriber
336       * @return a boolean
337       */

338      protected boolean isSubscribed(Subscriber subscriber) {
339          boolean isSubscribed = false;
340          List JavaDoc subscribedURIList = subscriber.getContext(this.repositoryName);
341          for (int i = 0; i < subscribedURIList.size(); i++) {
342              String JavaDoc uri = (String JavaDoc) subscribedURIList.get(i);
343              if (this.path.equals(uri)) {
344                  isSubscribed = true;
345              }
346              else if (this.path.startsWith(uri + "/")) { //$NON-NLS-1$
347
isSubscribed = true;
348              }
349              else if (uri.endsWith("/") && (this.path.startsWith(uri))) { //$NON-NLS-1$
350
isSubscribed = true;
351              }
352          }
353          return isSubscribed;
354      }
355
356      /**
357       * @param path , to deactivate
358       * @throws RepositoryException
359       * @throws ExchangeException
360       */

361      public synchronized void deActivate(String JavaDoc path) throws ExchangeException, RepositoryException {
362          this.path = path;
363          this.doDeActivate();
364          updateDeActivationDetails();
365      }
366
367      /**
368       * @param path , to deactivate
369       * @param subscriber
370       * @throws RepositoryException
371       * @throws ExchangeException
372       */

373      public synchronized void deActivate(Subscriber subscriber, String JavaDoc path) throws ExchangeException,
374          RepositoryException {
375          throw new ExchangeException("Not implemented");
376      }
377
378      /**
379       * @throws ExchangeException
380       */

381      public abstract void doDeActivate() throws ExchangeException;
382
383      /**
384       * deactivate from a specified subscriber
385       * @param subscriber
386       * @throws ExchangeException
387       */

388      public abstract void doDeActivate(Subscriber subscriber) throws ExchangeException;
389
390      /**
391       * get deactivation URL
392       * @param subscriberInfo
393       */

394      protected String JavaDoc getDeactivationURL(Subscriber subscriberInfo) {
395          return getActivationURL(subscriberInfo);
396      }
397
398      /**
399       * add deactivation request header fields
400       * @param connection
401       */

402      protected void addDeactivationHeaders(URLConnection JavaDoc connection) {
403          connection.setRequestProperty(AUTHORIZATION, this.basicCredentials);
404          connection.addRequestProperty(REPOSITORY_NAME, this.repositoryName);
405          connection.addRequestProperty(WORKSPACE_NAME, this.workspaceName);
406          connection.addRequestProperty(PATH, this.path);
407          connection.addRequestProperty(ACTION, DE_ACTIVATE);
408      }
409
410      /**
411       * Get activation URL
412       * @param subscriberInfo
413       * @return activation handle
414       */

415      protected String JavaDoc getActivationURL(Subscriber subscriberInfo) {
416          return subscriberInfo.getURL() + DEFAULT_HANDLER;
417      }
418
419      /**
420       * add request headers needed for this activation
421       * @param connection
422       * @param activationContent
423       */

424      protected void addActivationHeaders(URLConnection JavaDoc connection, ActivationContent activationContent) {
425          Iterator JavaDoc headerKeys = activationContent.getProperties().keySet().iterator();
426          while (headerKeys.hasNext()) {
427              String JavaDoc key = (String JavaDoc) headerKeys.next();
428              String JavaDoc value = activationContent.getproperty(key);
429              connection.setRequestProperty(key, value);
430          }
431      }
432
433      /**
434       * Update activation meta data
435       * @throws RepositoryException
436       */

437      protected void updateActivationDetails() throws RepositoryException {
438          HierarchyManager hm = MgnlContext.getHierarchyManager(this.repositoryName, this.workspaceName);
439          Content page = hm.getContent(this.path);
440          updateMetaData(page, SimpleSyndicator.ACTIVATE);
441          page.save();
442      }
443
444      /**
445       * Update de-activation meta data
446       * @throws RepositoryException
447       */

448      protected void updateDeActivationDetails() throws RepositoryException {
449          HierarchyManager hm = MgnlContext.getHierarchyManager(this.repositoryName, this.workspaceName);
450          Content page = hm.getContent(this.path);
451          updateMetaData(page, SimpleSyndicator.DE_ACTIVATE);
452          page.save();
453      }
454
455      /**
456       * @param node
457       * @param type (activate / deactivate)
458       */

459      protected void updateMetaData(Content node, String JavaDoc type) throws AccessDeniedException {
460          // update the passed node
461
MetaData md = node.getMetaData();
462          if (type.equals(SimpleSyndicator.ACTIVATE)) {
463              md.setActivated();
464          }
465          else {
466              md.setUnActivated();
467          }
468          md.setActivatorId(this.user.getName());
469          md.setLastActivationActionDate();
470
471          Iterator JavaDoc children;
472          if (type.equals(SimpleSyndicator.ACTIVATE)) {
473              // use syndicator rulebased filter
474
children = node.getChildren(this.contentFilter).iterator();
475          }
476          else {
477              // all childs
478
children = node.getChildren(ContentUtil.EXCLUDE_META_DATA_CONTENT_FILTER).iterator();
479          }
480
481          while (children.hasNext()) {
482              Content child = (Content) children.next();
483              this.updateMetaData(child, type);
484          }
485
486
487      }
488
489      /**
490       * Collect Activation content
491       * @throws Exception
492       */

493      protected ActivationContent collect(Content node, List JavaDoc orderBefore) throws Exception JavaDoc {
494          ActivationContent activationContent = new ActivationContent();
495          // add global properties true for this path/hierarchy
496
activationContent.addProperty(PARENT_PATH, this.parent);
497          activationContent.addProperty(WORKSPACE_NAME, this.workspaceName);
498          activationContent.addProperty(REPOSITORY_NAME, this.repositoryName);
499          activationContent.addProperty(RESOURCE_MAPPING_FILE, "resources.xml");
500          activationContent.addProperty(ACTION, ACTIVATE);
501          activationContent.addProperty(CONTENT_FILTER_RULE, this.contentFilterRule.toString());
502          activationContent.addProperty(AUTHORIZATION, this.basicCredentials);
503
504          Document document = new Document();
505          Element root = new Element(RESOURCE_MAPPING_ROOT_ELEMENT);
506          document.setRootElement(root);
507          // collect exact order of this node within its same nodeType siblings
508
addOrderingInfo(root, orderBefore);
509
510          this.addResources(root, node.getWorkspace().getSession(), node, this.contentFilter, activationContent);
511          File resourceFile = File.createTempFile("resources", "", Path.getTempDirectory());
512          XMLOutputter outputter = new XMLOutputter();
513          outputter.output(document, new FileOutputStream(resourceFile));
514          // add resource file to the list
515
activationContent.addFile("resources.xml", resourceFile);
516
517          return activationContent;
518      }
519
520      /**
521       * add ardering info to the resource file mapping
522       * @param root element of the resource file under which ordering info must be added
523       * @param orderBefore
524       * */

525      protected void addOrderingInfo(Element root, List JavaDoc orderBefore) {
526          //do not use magnolia Content class since these objects are only meant for a single use to read UUID
527
Element siblingRoot = new Element(SIBLINGS_ROOT_ELEMENT);
528          root.addContent(siblingRoot);
529          if (orderBefore == null) return;
530          Iterator JavaDoc siblings = orderBefore.iterator();
531          while (siblings.hasNext()) {
532              String JavaDoc uuid = (String JavaDoc) siblings.next();
533              Element e = new Element(SIBLINGS_ELEMENT);
534              e.setAttribute(SIBLING_UUID, uuid);
535              siblingRoot.addContent(e);
536          }
537      }
538
539      /**
540       * @param resourceElement
541       * @param session
542       * @param content
543       * @param filter
544       * @param activationContent
545       * @throws IOException
546       * @throws RepositoryException
547       */

548      protected void addResources(Element resourceElement, Session session, Content content, Content.ContentFilter filter,
549                                ActivationContent activationContent) throws IOException, RepositoryException, SAXException JavaDoc, Exception JavaDoc {
550
551          File file = File.createTempFile("exchange" + content.getName(), "", Path.getTempDirectory());
552          GZIPOutputStream JavaDoc gzipOutputStream = new GZIPOutputStream JavaDoc(new FileOutputStream(file));
553
554          if (content.getWorkspace().getName().equalsIgnoreCase(ContentRepository.VERSION_STORE)) {
555              XMLReader JavaDoc elementfilter = new FrozenElementFilter(XMLReaderFactory
556                  .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName()));
557              ((FrozenElementFilter) elementfilter).setNodeName(content.getName());
558              /**
559               * nt:file node type has mandatory sub nodes
560               */

561              boolean noRecurse = !content.isNodeType(ItemType.NT_FILE);
562              exportAndParse(session, content, elementfilter, gzipOutputStream, noRecurse);
563          } else {
564              /**
565               * nt:file node type has mandatory sub nodes
566               */

567              if (content.isNodeType(ItemType.NT_FILE)) {
568                  session.exportSystemView(content.getJCRNode().getPath(), gzipOutputStream, false, false);
569              }
570              else {
571                  session.exportSystemView(content.getJCRNode().getPath(), gzipOutputStream, false, true);
572              }
573          }
574
575          IOUtils.closeQuietly(gzipOutputStream);
576          // add file entry in mapping.xml
577
Element element = new Element(RESOURCE_MAPPING_FILE_ELEMENT);
578          element.setAttribute(RESOURCE_MAPPING_NAME_ATTRIBUTE, content.getName());
579          element.setAttribute(RESOURCE_MAPPING_UUID_ATTRIBUTE, content.getUUID());
580          element.setAttribute(RESOURCE_MAPPING_ID_ATTRIBUTE, file.getName());
581          resourceElement.addContent(element);
582          // add this file element as resource in activation content
583
activationContent.addFile(file.getName(), file);
584
585          Iterator JavaDoc children = content.getChildren(filter).iterator();
586          while (children.hasNext()) {
587              Content child = (Content) children.next();
588              this.addResources(element, session, child, filter, activationContent);
589          }
590      }
591
592      /**
593       * @param session
594       * @param content
595       * @param elementfilter
596       * @param os
597       * @param noRecurse
598       * */

599      protected void exportAndParse(Session session,
600                                  Content content,
601                                  XMLReader JavaDoc elementfilter,
602                                  OutputStream JavaDoc os,
603                                  boolean noRecurse) throws Exception JavaDoc {
604          File tempFile = File.createTempFile("Frozen_"+content.getName(), "xml"); //$NON-NLS-1$ //$NON-NLS-2$
605
OutputStream JavaDoc tmpFileOutStream = null;
606          FileInputStream tmpFileInStream = null;
607          try {
608              tmpFileOutStream = new FileOutputStream(tempFile);
609              session.exportSystemView(content.getJCRNode().getPath(), tmpFileOutStream, false, noRecurse);
610              tmpFileOutStream.flush();
611              tmpFileOutStream.close();
612
613              OutputFormat outputFormat = new OutputFormat();
614              outputFormat.setPreserveSpace(false);
615
616              tmpFileInStream = new FileInputStream(tempFile);
617              elementfilter.setContentHandler(new XMLSerializer(os, outputFormat));
618              elementfilter.parse(new InputSource JavaDoc(tmpFileInStream));
619              tmpFileInStream.close();
620          } catch (Throwable JavaDoc t) {
621              log.error("Failed to parse XML using FrozenElementFilter",t);
622              throw new Exception JavaDoc(t);
623          } finally {
624              IOUtils.closeQuietly(tmpFileInStream);
625              IOUtils.closeQuietly(tmpFileOutStream);
626              tempFile.delete();
627          }
628      }
629
630
631 }
632
Popular Tags