com.day.cq.mcm.landingpage.parser.taghandlers.mbox.TargetComponentTagHandler Maven / Gradle / Ivy
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* ___________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.day.cq.mcm.landingpage.parser.taghandlers.mbox;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.dam.indd.PageComponent;
import com.day.cq.search.PredicateGroup;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.WCMException;
import com.day.cq.wcm.designimporter.DesignImportException;
import com.day.cq.wcm.designimporter.UnsupportedTagContentException;
import com.day.cq.wcm.designimporter.api.CanvasBuilder;
import com.day.cq.wcm.designimporter.api.ContainerComponentProvider;
import com.day.cq.wcm.designimporter.api.TagHandler;
import com.day.cq.wcm.designimporter.parser.HTMLContentType;
import com.day.cq.wcm.designimporter.parser.taghandlers.AbstractTagHandler;
import com.day.cq.wcm.designimporter.util.TagUtils;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.wrappers.ValueMapDecorator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
/**
* The target component tag handler is used to translate an any mbox component div
* into the target component.
*
*
* This tag handler is registered against the markup of type < div data-cq-component="target" >
* in {@link com.day.cq.wcm.designimporter.impl.TagHandlerProviderImpl}. That implies
* this tag handler will come into action whenever the design importer framework
* encounters an HTML tag matching the rule this handler is defined against.
*
*/
public class TargetComponentTagHandler extends AbstractTagHandler implements EventHandler,ContainerComponentProvider {
private String suffix;
private Map> experiences = new HashMap>();
private ServiceRegistration serviceRegistration;
private Logger logger = LoggerFactory.getLogger(TargetComponentTagHandler.class);
private String resourceType;
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws DesignImportException,
UnsupportedTagContentException {
super.startElement(uri, localName, qName, atts);
if (!(delegate instanceof MBoxExperienceTagHandler)) {
throw new UnsupportedTagContentException(
"Target component tag must only contain MBox experience tags");
}
}
@Override
public void characters(char[] ch, int start, int length) throws DesignImportException {
super.characters(ch, start, length);
if (delegate == null && new String(ch, start, length).trim().length() > 0) // Only WS characters allowed. Any text is not tolerable.
throw new UnsupportedTagContentException(
"Illicit HTML content encountered. Target component tag must only contain MBox experience tags.");
}
@Override
public void endElement(String uri, String localName, String qName) throws DesignImportException {
TagHandler lastDelegate = delegate;
super.endElement(uri, localName, qName);
if(delegate == null) {
// Implication - The lastDelegate has just completed handling
if(lastDelegate instanceof MBoxExperienceTagHandler && !((MBoxExperienceTagHandler) lastDelegate).isDefaultExperience()) {
String experience = ((MBoxExperienceTagHandler) lastDelegate).getSegment();
if(experience != null) {
List offerComponents = ((MBoxExperienceTagHandler) lastDelegate).getOfferComponents();
experiences.put(experience, offerComponents);
}
}
}
}
@Override
public void endHandling(String uri, String localName, String qName) throws DesignImportException {
super.endHandling(uri, localName, qName);
suffix = designImporterContext.componentSuffixGenerator.getSuffix("mbox");
Map base = new HashMap();
ValueMap properties = new ValueMapDecorator(base);
properties.put("nameHint", getNameHint());
PageComponent mbox = pageBuilder.createComponent(resourceType, properties, getNameHint());
if(pageComponents.size() <= 0) {
// Invalid? No default experience found
throw new UnsupportedTagContentException("No default experience component tag found. The mbox component tag must contain exactly one default experience component tag");
} else if(pageComponents.size() > 1) {
// Invalid!? More than one default experiences
throw new UnsupportedTagContentException("Multiple experience component tags found. The mbox component tag must contain exactly one default experience component tag");
} else {
PageComponent component = pageComponents.get(0);
PageComponent defaultComponent = pageBuilder.createComponent(component.getResourceType(), component.getProperties(), "default");
defaultComponent.getChildComponents().addAll(component.getChildComponents());
mbox.getChildComponents().add(defaultComponent);
}
pageComponents = new ArrayList();
pageComponents.add(mbox);
// Register for callback
String[] topics = new String[] {CanvasBuilder.EVENT_COMPLETE};
Dictionary props = new Hashtable();
props.put(EventConstants.EVENT_TOPIC, topics);
if(designImporterContext.bundleContext != null) {
serviceRegistration = designImporterContext.bundleContext.registerService(EventHandler.class.getName(), this , props);
}
}
private String getNameHint() {
return "mbox" + suffix;
}
@Override
public boolean supportsContent(HTMLContentType htmlContentType) {
if (htmlContentType == HTMLContentType.MARKUP)
return true;
else
return false;
}
@Override
public Object getContent(HTMLContentType htmlContentType) {
if (htmlContentType == HTMLContentType.MARKUP) {
String cqIncludeJspTag = " ";
return componentDivStartTag + cqIncludeJspTag + TagUtils.getMatchingEndTag(componentDivStartTag);
}
return null;
}
private BundleContext getBundleContext() {
return this.designImporterContext.bundleContext;
}
public void handleEvent(Event event) {
QueryBuilder queryBuilder;
ServiceReference ref = getBundleContext().getServiceReference(QueryBuilder.class.getName());
queryBuilder = (QueryBuilder) getBundleContext().getService(ref);
Query query = null;
String mboxComponentPath = null;
String mboxComponentName = "";
try {
Map map = new HashMap();
map.put("path", designImporterContext.page.getPath());
map.put("property", "nameHint");
map.put("property.value", getNameHint());
query = queryBuilder.createQuery(PredicateGroup.create(map), designImporterContext.designNode.getSession());
SearchResult result = query.getResult();
for (Hit hit : result.getHits()) {
mboxComponentPath = hit.getPath();
mboxComponentName = mboxComponentPath.replaceFirst(".*/","");
}
// Locate the experience and create the offer
for(Map.Entry> entry : experiences.entrySet()) {
String experience = entry.getKey();
List components = entry.getValue();
createExperienceIfNotExists(designImporterContext.page.getParent(), experience);
Map base = new HashMap();
ValueMap properties = new ValueMapDecorator(base);
PageComponent parsys = pageBuilder.createComponent("foundation/components/parsys", properties, "par");
parsys.getChildComponents().addAll(components);
components = new ArrayList();
components.add(parsys);
String pageRoot = designImporterContext.page.getParent().getPath() + "/" + experience;
String pageName = designImporterContext.page.getPath().replaceFirst(".*/", "") + "_" + mboxComponentName;
String pageTemplate = null;//"/libs/cq/personalization/templates/teaser";
Page page = pageBuilder.createPage(pageRoot, pageName, null, pageTemplate, null, components);
JcrUtil.setProperty(page.getContentResource().adaptTo(Node.class), "location", mboxComponentPath);
JcrUtil.setProperty(page.getContentResource().adaptTo(Node.class), "sling:resourceType", "cq/personalization/components/teaserpage"); //TODO: Without a resourceType, some page_added listener in analytics breaks
JcrUtil.setProperty(page.getContentResource().adaptTo(Node.class), JcrConstants.JCR_TITLE, page.getParent().getTitle());
}
} catch (WCMException e) {
logger.error("An exception occurred trying to create the offer page", e);
} catch (RepositoryException e) {
logger.error("An exception occurred trying to create the offer page", e);
}
if(serviceRegistration != null) {
serviceRegistration.unregister();
}
}
private void createExperienceIfNotExists(Page parent, String experience) throws RepositoryException, WCMException {
if(parent.adaptTo(Node.class).hasNode(experience))
return;
String pageRoot = parent.getPath();
String pageName = experience;
String pageTemplate = "/libs/cq/personalization/templates/experience";
Page page = pageBuilder.createPage(pageRoot, pageName, null, pageTemplate, null, new ArrayList());
Map map = new HashMap();
map.put("path", "/etc/segmentation");
map.put("nodename", experience);
map.put("property", "jcr:content/sling:resourceType");
map.put("property.value", "cq/personalization/components/segmentpage");
QueryBuilder queryBuilder;
ServiceReference ref = getBundleContext().getServiceReference(QueryBuilder.class.getName());
queryBuilder = (QueryBuilder) getBundleContext().getService(ref);
Query query = queryBuilder.createQuery(PredicateGroup.create(map), designImporterContext.designNode.getSession());
SearchResult result = query.getResult();
List segments = new ArrayList();
String experienceTitle = experience;
for (Hit hit : result.getHits()) {
String segmentPath = hit.getPath();
segments.add(segmentPath);
if(experienceTitle == experience) {
Node contentNode = hit.getNode().getNode(JcrConstants.JCR_CONTENT);
if(contentNode.hasProperty(JcrConstants.JCR_TITLE))
experienceTitle = contentNode.getProperty(JcrConstants.JCR_TITLE).getString();
}
}
if(segments.size() == 0) {
// log warning
designImporterContext.importWarnings.add("Segment " + experience + " not found. The target component might not work as expected.");
logger.warn("Segment " + experience + " not found. The target component might not work as expected.");
}
JcrUtil.setProperty(page.getContentResource().adaptTo(Node.class), "cq:segments", segments.toArray(new String[]{}));
JcrUtil.setProperty(page.getContentResource().adaptTo(Node.class), JcrConstants.JCR_TITLE, experienceTitle);
}
public void setResourcetype(String resourceType) {
this.resourceType = resourceType;
}
}