1 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 ; 25 import org.xml.sax.XMLReader ; 26 import org.xml.sax.InputSource ; 27 import org.xml.sax.helpers.XMLReaderFactory ; 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 ; 44 import java.util.Iterator ; 45 import java.util.zip.GZIPOutputStream ; 46 import java.net.URLConnection ; 47 import java.io.*; 48 49 53 public abstract class BaseSyndicatorImpl implements Syndicator { 54 55 58 public static final String DEFAULT_HANDLER = "ActivationHandler"; 60 63 public static final String PARENT_PATH = "mgnlExchangeParentPath"; 64 65 68 public static final String PATH = "mgnlExchangePath"; 69 70 73 public static final String REPOSITORY_NAME = "mgnlExchangeRepositoryName"; 74 75 78 public static final String WORKSPACE_NAME = "mgnlExchangeWorkspaceName"; 79 80 83 public static final String RESOURCE_MAPPING_FILE = "mgnlExchangeResourceMappingFile"; 84 85 90 public static final String SIBLINGS_ROOT_ELEMENT = "NodeSiblings"; 91 92 95 public static final String SIBLINGS_ELEMENT = "sibling"; 96 97 100 public static final String SIBLING_UUID = "UUID"; 101 102 105 public static final String RESOURCE_MAPPING_FILE_ELEMENT = "File"; 106 107 110 public static final String RESOURCE_MAPPING_NAME_ATTRIBUTE = "name"; 111 112 115 public static final String RESOURCE_MAPPING_UUID_ATTRIBUTE = "contentUUID"; 116 117 120 public static final String RESOURCE_MAPPING_ID_ATTRIBUTE = "resourceId"; 121 122 125 public static final String RESOURCE_MAPPING_ROOT_ELEMENT = "Resources"; 126 127 130 public static final String ACTION = "mgnlExchangeAction"; 131 132 135 public static final String ACTIVATE = "activate"; 137 140 public static final String DE_ACTIVATE = "deactivate"; 142 145 public static final String AUTHORIZATION = "Authorization"; 146 147 150 public static final String CONTENT_FILTER_RULE = "mgnlExchangeFilterRule"; 151 152 155 public static final String ACTIVATION_SUCCESSFUL = "sa_success"; 157 public static final String ACTIVATION_FAILED = "sa_failed"; 159 public static final String ACTIVATION_ATTRIBUTE_STATUS = "sa_attribute_status"; 161 public static final String ACTIVATION_ATTRIBUTE_MESSAGE = "sa_attribute_message"; 163 166 private static Logger log = LoggerFactory.getLogger(SimpleSyndicator.class); 167 168 protected String repositoryName; 169 170 protected String workspaceName; 171 172 protected String parent; 173 174 protected String path; 175 176 protected Content.ContentFilter contentFilter; 177 178 protected Rule contentFilterRule; 179 180 protected User user; 181 182 protected String basicCredentials; 183 184 192 public void init(User user, String repositoryName, String workspaceName, Rule rule) { 193 this.user = user; 194 this.basicCredentials = "Basic " 195 + new String (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 210 public synchronized void activate(String parent, String 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 224 public void activate(String parent, Content content) throws ExchangeException, RepositoryException { 225 this.activate(parent, content, null); 226 } 227 228 240 public void activate(String parent, Content content, List 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 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 274 public void activate(Subscriber subscriber, String parent, Content content) 275 throws ExchangeException, RepositoryException { 276 throw new ExchangeException("Not implemented"); 277 } 278 279 292 public void activate(Subscriber subscriber, String parent, Content content, List orderBefore) 293 throws ExchangeException, RepositoryException { 294 throw new ExchangeException("Not implemented"); 295 } 296 297 300 public abstract void activate(ActivationContent activationContent) throws ExchangeException; 301 302 303 309 public abstract void activate(Subscriber subscriber, ActivationContent activationContent) 310 throws ExchangeException; 311 312 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 keys = activationContent.getFiles().keySet().iterator(); 324 while (keys.hasNext()) { 325 String key = (String ) keys.next(); 326 if (log.isDebugEnabled()) { 327 log.debug("Removing temporary file {}", key); 328 } 329 activationContent.getFile(key).delete(); 330 } 331 } 332 333 338 protected boolean isSubscribed(Subscriber subscriber) { 339 boolean isSubscribed = false; 340 List subscribedURIList = subscriber.getContext(this.repositoryName); 341 for (int i = 0; i < subscribedURIList.size(); i++) { 342 String uri = (String ) subscribedURIList.get(i); 343 if (this.path.equals(uri)) { 344 isSubscribed = true; 345 } 346 else if (this.path.startsWith(uri + "/")) { isSubscribed = true; 348 } 349 else if (uri.endsWith("/") && (this.path.startsWith(uri))) { isSubscribed = true; 351 } 352 } 353 return isSubscribed; 354 } 355 356 361 public synchronized void deActivate(String path) throws ExchangeException, RepositoryException { 362 this.path = path; 363 this.doDeActivate(); 364 updateDeActivationDetails(); 365 } 366 367 373 public synchronized void deActivate(Subscriber subscriber, String path) throws ExchangeException, 374 RepositoryException { 375 throw new ExchangeException("Not implemented"); 376 } 377 378 381 public abstract void doDeActivate() throws ExchangeException; 382 383 388 public abstract void doDeActivate(Subscriber subscriber) throws ExchangeException; 389 390 394 protected String getDeactivationURL(Subscriber subscriberInfo) { 395 return getActivationURL(subscriberInfo); 396 } 397 398 402 protected void addDeactivationHeaders(URLConnection 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 415 protected String getActivationURL(Subscriber subscriberInfo) { 416 return subscriberInfo.getURL() + DEFAULT_HANDLER; 417 } 418 419 424 protected void addActivationHeaders(URLConnection connection, ActivationContent activationContent) { 425 Iterator headerKeys = activationContent.getProperties().keySet().iterator(); 426 while (headerKeys.hasNext()) { 427 String key = (String ) headerKeys.next(); 428 String value = activationContent.getproperty(key); 429 connection.setRequestProperty(key, value); 430 } 431 } 432 433 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 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 459 protected void updateMetaData(Content node, String type) throws AccessDeniedException { 460 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 children; 472 if (type.equals(SimpleSyndicator.ACTIVATE)) { 473 children = node.getChildren(this.contentFilter).iterator(); 475 } 476 else { 477 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 493 protected ActivationContent collect(Content node, List orderBefore) throws Exception { 494 ActivationContent activationContent = new ActivationContent(); 495 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 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 activationContent.addFile("resources.xml", resourceFile); 516 517 return activationContent; 518 } 519 520 525 protected void addOrderingInfo(Element root, List orderBefore) { 526 Element siblingRoot = new Element(SIBLINGS_ROOT_ELEMENT); 528 root.addContent(siblingRoot); 529 if (orderBefore == null) return; 530 Iterator siblings = orderBefore.iterator(); 531 while (siblings.hasNext()) { 532 String uuid = (String ) siblings.next(); 533 Element e = new Element(SIBLINGS_ELEMENT); 534 e.setAttribute(SIBLING_UUID, uuid); 535 siblingRoot.addContent(e); 536 } 537 } 538 539 548 protected void addResources(Element resourceElement, Session session, Content content, Content.ContentFilter filter, 549 ActivationContent activationContent) throws IOException, RepositoryException, SAXException , Exception { 550 551 File file = File.createTempFile("exchange" + content.getName(), "", Path.getTempDirectory()); 552 GZIPOutputStream gzipOutputStream = new GZIPOutputStream (new FileOutputStream(file)); 553 554 if (content.getWorkspace().getName().equalsIgnoreCase(ContentRepository.VERSION_STORE)) { 555 XMLReader elementfilter = new FrozenElementFilter(XMLReaderFactory 556 .createXMLReader(org.apache.xerces.parsers.SAXParser.class.getName())); 557 ((FrozenElementFilter) elementfilter).setNodeName(content.getName()); 558 561 boolean noRecurse = !content.isNodeType(ItemType.NT_FILE); 562 exportAndParse(session, content, elementfilter, gzipOutputStream, noRecurse); 563 } else { 564 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 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 activationContent.addFile(file.getName(), file); 584 585 Iterator 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 599 protected void exportAndParse(Session session, 600 Content content, 601 XMLReader elementfilter, 602 OutputStream os, 603 boolean noRecurse) throws Exception { 604 File tempFile = File.createTempFile("Frozen_"+content.getName(), "xml"); OutputStream 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 (tmpFileInStream)); 619 tmpFileInStream.close(); 620 } catch (Throwable t) { 621 log.error("Failed to parse XML using FrozenElementFilter",t); 622 throw new Exception (t); 623 } finally { 624 IOUtils.closeQuietly(tmpFileInStream); 625 IOUtils.closeQuietly(tmpFileOutStream); 626 tempFile.delete(); 627 } 628 } 629 630 631 } 632 | Popular Tags |