com.day.cq.wcm.foundation.List Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*
* Copyright 1997-2008 Day Management AG
* Barfuesserplatz 6, 4001 Basel, Switzerland
* All Rights Reserved.
*
* This software is the confidential and proprietary information of
* Day Management AG, ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Day.
*/
package com.day.cq.wcm.foundation;
import com.day.cq.commons.Filter;
import com.day.cq.commons.RangeIterator;
import com.day.cq.search.Predicate;
import com.day.cq.search.Query;
import com.day.cq.search.QueryBuilder;
import com.day.cq.search.SimpleSearch;
import com.day.cq.search.result.Hit;
import com.day.cq.search.result.SearchResult;
import com.day.cq.tagging.Tag;
import com.day.cq.tagging.TagManager;
import com.day.cq.wcm.api.NameConstants;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageFilter;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.WCMException;
import com.day.cq.wcm.api.Template;
import com.day.text.Text;
import org.apache.commons.collections4.iterators.EmptyIterator;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFormatException;
import javax.jcr.query.QueryResult;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Locale;
/**
* Creates a list from a resource for use in the list component.
*/
public class List {
public static final Logger log = LoggerFactory.getLogger(List.class);
public static final String DEFAULT_QUERY = "";
public static final String URL_EXTENSION = ".html";
public static final String TYPE_PROPERTY_NAME = "displayAs";
public static final String SOURCE_PROPERTY_NAME = "listFrom";
/**
* Used to create a list from child pages.
*/
public static final String SOURCE_CHILDREN = "children";
/**
* Used to create a list from descendant pages.
*/
public static final String SOURCE_DESCENDANTS = "descendants";
/**
* Used to create a list from a fixed selection of pages.
*/
public static final String SOURCE_STATIC = "static";
/**
* Used to create a list from a search result.
*/
public static final String SOURCE_SEARCH = "search";
/**
* Used to create a list from a querybuilder search result. Allows rendering of any node, not just pages.
*/
public static final String SOURCE_QUERYBUILDER = "querybuilder";
/**
* Used to create a list from list of tags.
*/
public static final String SOURCE_TAGS = "tags";
/**
* Used for default rendering of the list items.
*/
public static final String TYPE_DEFAULT = "default";
public static final String PARENT_PAGE_PROPERTY_NAME = "parentPage";
public static final String ANCESTOR_PAGE_PROPERTY_NAME = "ancestorPage";
public static final String TAGS_SEARCH_ROOT_PROPERTY_NAME = "tagsSearchRoot";
public static final String TAGS_PROPERTY_NAME = "tags";
public static final String TAGS_MATCH_PROPERTY_NAME = "tagsMatch";
public static final String PAGES_PROPERTY_NAME = "pages";
public static final String QUERY_PROPERTY_NAME = "query";
public static final String SEARCH_IN_PROPERTY_NAME = "searchIn";
public static final String SEARCH_PROPERTY = ".";
public static final String LIMIT_PROPERTY_NAME = "limit";
public static final String PAGE_MAX_PROPERTY_NAME = "pageMax";
public static final String ORDER_BY_PROPERTY_NAME = "orderBy";
public static final String ORDERED_PROPERTY_NAME = "ordered";
public static final String SAVEDQUERY_PROPERTY_NAME = "savedquery";
public static final String PAGE_START_PARAM_NAME = "start";
public static final String PAGE_MAX_PARAM_NAME = "max";
public static final String ALLOW_DUPLICATES_PROPERTY_NAME = "allowDuplicates";
private String id;
private SlingHttpServletRequest request;
private java.util.List resources;
private java.util.List pages;
private Iterator pageIterator;
private Iterator nodeIterator;
private boolean inited;
private boolean ordered;
private String source;
private String query;
private String queryType;
private String startIn;
private String type;
private String orderBy;
private Comparator orderComparator;
private int limit = -1;
private int pageMaximum = -1;
private int pageStart = 0;
private Resource resource;
private ValueMap properties;
private PageFilter pageFilter;
/**
* Creates a List
instance based on the specified request.
* @param request The request
*/
public List(SlingHttpServletRequest request) {
this(request, null);
}
/**
* Creates a List
instance based on the specified request.
*
* @param request The request
* @param pageFilter Page filter
*/
public List(SlingHttpServletRequest request, PageFilter pageFilter) {
this.request = request;
this.pageFilter = pageFilter;
resource = request.getResource();
generateId();
}
private void initConfig() {
// get config from content
properties = ResourceUtil.getValueMap(resource);
if (source == null) {
source = properties.get(SOURCE_PROPERTY_NAME, SOURCE_STATIC);
}
if (query == null) {
query = properties.get(QUERY_PROPERTY_NAME, DEFAULT_QUERY);
}
if (startIn == null) {
startIn = properties.get(SEARCH_IN_PROPERTY_NAME, Text.getAbsoluteParent(resource.getPath(), 1));
}
if (type == null) {
type = properties.get(TYPE_PROPERTY_NAME, TYPE_DEFAULT);
}
if (orderBy == null) {
orderBy = properties.get(ORDER_BY_PROPERTY_NAME, String.class);
}
if (limit < 0) {
limit = properties.get(LIMIT_PROPERTY_NAME, 100);
}
if (pageMaximum < 0) {
pageMaximum = properties.get(PAGE_MAX_PROPERTY_NAME, -1);
}
ordered = properties.get(ORDERED_PROPERTY_NAME, ordered);
// get config from request parameters
if (getParameter(PAGE_START_PARAM_NAME) != null) {
try {
pageStart = Integer.parseInt(getParameter(PAGE_START_PARAM_NAME));
} catch (Throwable t) {
// ignore
}
}
if (getParameter(PAGE_MAX_PARAM_NAME) != null) {
try {
pageMaximum = Integer.parseInt(getParameter(PAGE_MAX_PARAM_NAME));
} catch (Throwable t) {
// ignore
}
}
}
@SuppressWarnings("unchecked")
private boolean init() {
if (!inited) {
initConfig();
// Note: this iter can also be set from the outside (setPageIterator())
if (pageIterator == null) {
ResourceResolver resolver = request.getResourceResolver();
PageManager pm = resolver.adaptTo(PageManager.class);
// per default we don't want duplicate pages in the result
boolean allowDuplicates = properties.get(ALLOW_DUPLICATES_PROPERTY_NAME, false);
try {
Session session = resolver.adaptTo(Session.class);
// advanced search = querybuilder
if (SOURCE_QUERYBUILDER.equals(source)) {
QueryBuilder queryBuilder = resolver.adaptTo(QueryBuilder.class);
if (session != null && queryBuilder != null) {
try {
Query query = queryBuilder.loadQuery(resource.getPath() + "/" + SAVEDQUERY_PROPERTY_NAME, session);
if (query != null) {
SearchResult result = query.getResult();
// store as both page and node iterator
pageIterator = new HitBasedPageIterator(pm, result.getHits().iterator(), !allowDuplicates, this.pageFilter);
nodeIterator = result.getNodes();
}
} catch (Exception e) {
log.error("error loading stored querybuilder query from " + resource.getPath(), e);
}
}
// simple search
} else if (SOURCE_SEARCH.equals(source)) {
if (DEFAULT_QUERY.equals(query)) {
pageIterator = EmptyIterator.INSTANCE;
}
if (queryType != null) {
javax.jcr.query.Query jcrQuery = session.getWorkspace().getQueryManager().createQuery(query, queryType);
QueryResult result = jcrQuery.execute();
pageIterator = new NodeBasedPageIterator(pm, result.getNodes(), !allowDuplicates, this.pageFilter);
} else {
SimpleSearch search = getSearch(resource.getPath());
search.setQuery(query);
search.setSearchIn(startIn);
search.setSearchProperties(SEARCH_PROPERTY);
// ensure we only get pages
search.addPredicate(new Predicate("type", "type").set("type", NameConstants.NT_PAGE));
search.setHitsPerPage(100000);
// run simple search
SearchResult result = search.getResult();
pageIterator = new HitBasedPageIterator(pm, result.getHits().iterator(), !allowDuplicates, this.pageFilter);
}
// list child or descendant pages
} else if (SOURCE_CHILDREN.equals(source) || SOURCE_DESCENDANTS.equals(source)){
String parentPath = null;
boolean deep = false;
// default to current page
if (SOURCE_CHILDREN.equals(source)) {
parentPath = properties.get(PARENT_PAGE_PROPERTY_NAME, resource.getPath());
} else if (SOURCE_DESCENDANTS.equals(source)) {
deep = true;
parentPath = properties.get(ANCESTOR_PAGE_PROPERTY_NAME, resource.getPath());
}
Page startPage = pm.getContainingPage(parentPath);
if (startPage != null) {
// only get pages that are valid (on/off times, hide in nav)
// Use default page filter if there is no page filter, because it was working this way
// before adding PageFilter support
Filter pageFilter = this.pageFilter != null ? this.pageFilter : new PageFilter();
pageIterator = startPage.listChildren(pageFilter, deep);
} else {
pageIterator = EmptyIterator.INSTANCE;
}
// list from tags
} else if (SOURCE_TAGS.equals(source)) {
// default to current page
String parentPath = properties.get(TAGS_SEARCH_ROOT_PROPERTY_NAME, resource.getPath());
String[] tags = properties.get(TAGS_PROPERTY_NAME, new String[0]);
boolean matchAny = properties.get(TAGS_MATCH_PROPERTY_NAME, "any").equals("any");
Page startPage = pm.getContainingPage(parentPath);
if (startPage != null && tags.length > 0) {
TagManager tagManager = request.getResourceResolver().adaptTo(TagManager.class);
RangeIterator results = tagManager.find(startPage.getPath(), tags, matchAny);
LinkedHashMap pages = new LinkedHashMap();
while (results.hasNext()) {
Resource r = results.next();
Page page = pm.getContainingPage(r);
if (page != null && (pageFilter == null || pageFilter.includes(page))) {
pages.put(page.getPath(), page);
}
}
pageIterator = pages.values().iterator();
} else {
pageIterator = EmptyIterator.INSTANCE;
}
// fixed list of pages
} else {
ArrayList staticPages = new ArrayList();
String[] statics = properties.get(PAGES_PROPERTY_NAME, new String[0]);
for (String path : statics) {
Page p = pm.getContainingPage(path);
if (p != null && (pageFilter == null || pageFilter.includes(p))) {
staticPages.add(p);
}
}
pageIterator = staticPages.iterator();
}
} catch (Exception e) {
log.error("error creating page iterator", e);
}
}
pages = new ArrayList();
resources = new ArrayList();
if (pageIterator == null) {
return false;
}
// build list of pages and resources from page iterator
while (pageIterator.hasNext()) {
PageWrapper wrappedPage = new PageWrapperImpl(pageIterator.next());
pages.add(wrappedPage);
}
// apply sort order if present
if (orderComparator != null) {
Collections.sort(pages, orderComparator);
} else if (orderBy != null) {
Collections.sort(pages, new PageComparator(orderBy));
}
// apply limit
if (pages.size() > limit) {
pages = pages.subList(0, limit);
}
for (Page p : pages) {
resources.add(p.getContentResource());
}
inited = true;
}
return true;
}
private void generateId() {
String path = resource.getPath();
String rootMarker = "jcr:content/";
int root = path.indexOf(rootMarker);
if (root >= 0) {
path = path.substring(root + rootMarker.length());
}
id = path.replace('/', '_');
}
private SimpleSearch getSearch(String path) {
try {
Resource res = request.getResourceResolver().getResource(path);
SimpleSearch search = res.adaptTo(SimpleSearch.class);
if (search != null) {
return search;
}
} catch (Exception e) {
// ignore
}
if (path.lastIndexOf("/") > 0) {
return getSearch(Text.getRelativeParent(path, 1));
}
return null;
}
private String getParameter(String name) {
return request.getParameter(id + "_" + name);
}
/**
* Returns the list items as resources.
* @return The resources
* @deprecated use {@link List#getPages()} instead
*/
public Iterator getResources() {
return init() && resources.size() > 0 ? resources.iterator() : null;
}
/**
* Returns the list items as pages, respecting both starting index and
* maximum number of list items if specified.
* @return The pages
*/
public Iterator getPages() {
if (init() && pages.size() > 0) {
ArrayList plist = new ArrayList();
int c = 0;
for (int i = 0; i < pages.size(); i++) {
if (i < pageStart) {
continue;
}
plist.add(pages.get(i));
c++;
if (pageMaximum > 0 && c == pageMaximum) {
break;
}
}
return plist.iterator();
} else {
return null;
}
}
/**
* Returns the list as nodes. This is only the case when an advanced search
* is run, ie. the {@link #setSource(String) source} is
* {@link #SOURCE_QUERYBUILDER}. Otherwise null
will be
* returned.
*
* @return the nodes of a querybuilder search result or null
* @since 5.3
*/
public Iterator getNodes() {
return init() ? nodeIterator : null;
}
/**
* States whether the list is ordered.
* @return true
if list is ordered, false
otherwise
*/
public boolean isOrdered() {
return ordered;
}
/**
* States whether the list is empty.
* @return true
if list is empty, false
otherwise
*/
public boolean isEmpty() {
return !init() || resources.isEmpty();
}
/**
* Returns the number of list items.
* @return The size of the list
*/
public int size() {
return init() ? resources.size() : 0;
}
/**
* States whether the list is paginating, i.e. has a starting index
* and/or a maximum numbe rof list items per page defined.
* @return true
if list is paginating, false
otherwise
*/
public boolean isPaginating() {
return pageStart > 0 || (pageMaximum > 0 && size() > pageMaximum);
}
/**
* Returns the starting index for list items on this page.
* Used for pagination.
* @return The start index of
*/
public int getPageStart() {
return pageStart;
}
/**
* Returns the maximum of list items to return per page.
* Used for pagination.
* @return The maximum per page
*/
public int getPageMaximum() {
return pageMaximum;
}
/**
* Returns the link to the page with the next set of list items.
* Used for pagination.
* @return The link to the next page
*/
public String getNextPageLink() {
if (isPaginating() && pageMaximum > 0) {
if (pageStart + pageMaximum < size()) {
int start = pageStart + pageMaximum;
PageLink link = new PageLink(request);
link.setParameter(PAGE_START_PARAM_NAME, start);
return link.toString();
}
}
return null;
}
/**
* Returns the link to the page with the previous set of list items.
* Used for pagination.
* @return The link to the previous page
*/
public String getPreviousPageLink() {
if (isPaginating()) {
if (pageStart > 0) {
int start = pageMaximum > 0 && pageStart > pageMaximum ?
pageStart - pageMaximum : 0;
PageLink link = new PageLink(request);
link.setParameter(PAGE_START_PARAM_NAME, start);
return link.toString();
}
}
return null;
}
/**
* Sets the source for the list. The value can be one of:
*
* - {@link #SOURCE_CHILDREN}
* - {@link #SOURCE_SEARCH}
* - {@link #SOURCE_STATIC}
* - {@link #SOURCE_QUERYBUILDER}
*
* This is an optional setter, the default value will be
* taken from the property defined by {@link #SOURCE_PROPERTY_NAME}.
* @param src The list source
*/
public void setSource(String src) {
source = src;
}
/**
* Sets the query for the fulltext search.
* @param q The query
*/
public void setQuery(String q) {
setQuery(q, null);
}
/**
* Sets the query for the search with the specified type (xpath, sql).
* @param q The query
* @param type The query type (optional)
*/
public void setQuery(String q, String type) {
query = q;
queryType = type;
}
/**
* Sets the the of the page to start searching on.
* @param start The start page path
*/
public void setStartIn(String start) {
startIn = start;
}
/**
* Returns the type of the list. This can be used to select the
* script that renders the list items.
* @return The list type
*/
public String getType() {
return type;
}
/**
* Sets the type of the list.
* This is an optional setter, the default value will be
* taken from the property defined by {@link #TYPE_PROPERTY_NAME}.
* @param t The list type
*/
public void setType(String t) {
type = t;
}
/**
* Sets the comparator used to order the list with.
* This is an optional setter and overrides #setOrderBy(String).
* @param obc The comparator to order the list with
*/
public void setOrderComparator(Comparator obc) {
orderComparator = obc;
}
/**
* Sets the property to order the list by.
* This is an optional setter, the default value will be
* taken from the property defined by {@link #ORDER_BY_PROPERTY_NAME}.
* @param ob The property to order the list by
*/
public void setOrderBy(String ob) {
orderBy = ob;
}
/**
* Sets the list style (numbered or not).
* This is an optional setter, the default value will be false
* @param o true
if list should be rendered with numbered items,
* false
otherwise
*/
public void setOrdered(boolean o) {
ordered = o;
}
/**
* Sets the limit for list items.
* This is an optional setter, the default value will be
* taken from the property defined by {@link #LIMIT_PROPERTY_NAME}.
* @param l The limit
*/
public void setLimit(int l) {
limit = l;
}
/**
* Sets the maximum list items to return. Enables pagination.
* This is an optional setter, the default value will be
* taken from the property defined by {@link #PAGE_MAX_PROPERTY_NAME}.
* @param pm The maximum number of pages per page
*/
public void setPageMaximum(int pm) {
pageMaximum = pm;
}
/**
* Sets the starting index to be respected when returning
* list items. Used when paginating.
* @param psi The starting index (defaults to 0).
*/
public void setPageStart(int psi) {
pageStart = psi;
}
/**
* Sets the page iterator to generate the list from.
* @param iter The iterator
*/
public void setPageIterator(Iterator iter) {
pageIterator = iter;
setSource(SOURCE_STATIC);
}
/**
* Compares pages with each other by property.
*/
public class PageComparator implements Comparator
{
private String property;
private boolean orderByJcrCreated;
private static final String JCR_CREATED = "jcr:created";
/**
* Creates a PageComparator
instance using the
* specified property for comparison.
* @param prop The name of the property
*/
public PageComparator(String prop) {
property = prop;
orderByJcrCreated = isOrderByJcrCreated(prop);
}
/**
* {@inheritDoc}
*/
public int compare(P p1, P p2) {
int comp = getKey(p1).compareTo(getKey(p2));
return (comp != 0 && isDate(p1, property) && isDate(p2, property)) ? -comp : comp;
}
/**
* For ordering child pages in the list we prefer the cq:page's node
* {@link #JCR_CREATED} property when we select orderBy as {@link #JCR_CREATED}, instead of
* using jcr:content's node {@link #JCR_CREATED} property for ordering. This makes sure
* when a child page is published, its order is retained.
* @param p The page in context
* @return The value of property for the page
*/
private String getKey(P p) {
if (orderByJcrCreated) {
if (PageWrapper.class.isAssignableFrom(p.getClass())) {
ValueMap pageNodeMap = ((PageWrapper)p).getRootResource().getValueMap();
return pageNodeMap.get(property, "");
}
}
return p.getProperties().get(property, "");
}
/*
* Checks if the property 'prop' of the given page is a JCR property of type Date.
*/
private boolean isDate(Page page, String prop) {
if (page == null || page.getContentResource() == null) {
return false;
}
Node pageContentNode = page.getContentResource().adaptTo(Node.class);
Calendar date = null;
try {
Property property = pageContentNode.getProperty(prop);
if (property == null) {
return false;
}
date = property.getDate();
} catch (ValueFormatException vfe) {
return false;
} catch (RepositoryException re) {
return false;
}
return date != null;
}
private boolean isOrderByJcrCreated(String prop){
return prop.matches(JCR_CREATED);
}
}
/**
* A helper class to create links with query parameters.
*/
private class PageLink {
private String path;
private HashMap params;
public PageLink(SlingHttpServletRequest request) {
path = request.getPathInfo();
// Get containing page from path and replace path with its path
PageManager pm = request.getResourceResolver().adaptTo(PageManager.class);
Page page = pm.getContainingPage(path);
if (page != null) {
path = page.getPath() + URL_EXTENSION;
}
initParams(request.getQueryString());
}
public void addParameter(String name, Object value) {
name = prefixName(name);
params.put(name, value);
}
public void setParameter(String name, Object value) {
name = prefixName(name);
if (params.containsKey(name)) {
params.remove(name);
}
addParameter(name, value);
}
public String toString() {
String url = path;
for (String param : params.keySet()) {
url = appendParam(url, param, params.get(param));
}
return url;
}
private String prefixName(String name) {
if (!name.startsWith(id + "_")) {
name = id + "_" + name;
}
return name;
}
private void initParams(String query) {
params = new HashMap();
String[] pairs = Text.explode(query, '&');
for (String pair : pairs) {
String[] param = Text.explode(pair, '=', true);
params.put(param[0], param[1]);
}
}
private String appendParam(String url, String name, Object value) {
char delim = url.indexOf('?') > 0 ? '&' : '?';
return new StringBuffer(url)
.append(delim)
.append(name)
.append('=')
.append(value).toString();
}
}
/**
* An abstract base class for page iterators.
*/
private abstract class AbstractPageIterator implements Iterator {
protected PageManager pm;
protected Page nextPage;
// keeps track of pages seen
protected Set seen;
// Filter pages
protected PageFilter pageFilter;
public boolean hasNext() {
return nextPage != null;
}
public Page next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Page page = nextPage;
nextPage = seek();
return page;
}
protected abstract Page seek();
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* A helper class that iterates over the pages behind a node iterator.
*/
private class NodeBasedPageIterator extends AbstractPageIterator {
private NodeIterator nodes;
public NodeBasedPageIterator(PageManager pm, NodeIterator nodes, boolean avoidDuplicates, PageFilter pageFilter) {
this.pm = pm;
this.nodes = nodes;
if (avoidDuplicates) {
this.seen = new HashSet();
}
this.pageFilter = pageFilter;
this.nextPage = seek();
}
protected Page seek() {
while (nodes != null && nodes.hasNext()) {
try {
Page page = pm.getContainingPage(nodes.nextNode().getPath());
// only return if duplicates are allowed or if page wasn't seen yet
if (page != null && (seen == null || seen.add(page.getPath())) && (pageFilter == null || pageFilter.includes(page))) {
return page;
}
} catch (Exception e) {
log.error("Could not get page behind result node", e);
}
}
return null;
}
}
/**
* A helper class that iterates over the pages behind a hit iterator.
*/
private class HitBasedPageIterator extends AbstractPageIterator {
private Iterator hits;
public HitBasedPageIterator(PageManager pm, Iterator hits, boolean avoidDuplicates, PageFilter pageFilter) {
this.pm = pm;
this.hits = hits;
if (avoidDuplicates) {
this.seen = new HashSet();
}
this.pageFilter = pageFilter;
this.nextPage = seek();
}
protected Page seek() {
while (hits != null && hits.hasNext()) {
try {
Page page = pm.getContainingPage(hits.next().getResource());
// only return if duplicates are allowed or if page wasn't seen yet
if (page != null && (seen == null || seen.add(page.getPath())) && (pageFilter == null || pageFilter.includes(page))) {
return page;
}
} catch (Exception e) {
log.error("Could not get page behind search result hit", e);
}
}
return null;
}
}
private interface PageWrapper extends Page{
/**
* Returns the resource node of the cq:page node.
* @return Resource for the page in context
*/
Resource getRootResource();
}
/**
* Wrapper class of Page internally caching the root resource node.
*/
private class PageWrapperImpl implements PageWrapper{
private Page page;
private Resource resource;
public PageWrapperImpl(Page page){
this.page = page;
}
@Override
public Resource getRootResource() {
if (resource == null) {
resource = page.adaptTo(Resource.class);
}
return resource;
}
@Override
public String getDescription() {
return page.getDescription();
}
@Override
public AdapterType adaptTo(Class aClass) {
return page.adaptTo(aClass);
}
@Override
public String getPath() {
return page.getPath();
}
@Override
public PageManager getPageManager() {
return page.getPageManager();
}
@Override
public Resource getContentResource() {
return page.getContentResource();
}
@Override
public Resource getContentResource(String s) {
return page.getContentResource(s);
}
@Override
public Iterator listChildren() {
return page.listChildren();
}
@Override
public Iterator listChildren(Filter filter) {
return page.listChildren(filter);
}
@Override
public Iterator listChildren(Filter filter, boolean b) {
return page.listChildren(filter,b);
}
@Override
public boolean hasChild(String s) {
return page.hasChild(s);
}
@Override
public int getDepth() {
return page.getDepth();
}
@Override
public Page getParent() {
return page.getParent();
}
@Override
public Page getParent(int i) {
return page.getParent(i);
}
@Override
public Page getAbsoluteParent(int i) {
return page.getAbsoluteParent(i);
}
@Override
public ValueMap getProperties() {
return page.getProperties();
}
@Override
public ValueMap getProperties(String s) {
return page.getProperties(s);
}
@Override
public String getName() {
return page.getName();
}
@Override
public String getTitle() {
return page.getTitle();
}
@Override
public String getPageTitle() {
return page.getPageTitle();
}
@Override
public String getNavigationTitle() {
return page.getNavigationTitle();
}
@Override
public boolean isHideInNav() {
return page.isHideInNav();
}
@Override
public boolean hasContent() {
return page.hasContent();
}
@Override
public boolean isValid() {
return page.isValid();
}
@Override
public long timeUntilValid() {
return page.timeUntilValid();
}
@Override
public Calendar getOnTime() {
return page.getOnTime();
}
@Override
public Calendar getOffTime() {
return page.getOffTime();
}
@Override
public Calendar getDeleted() {
return page.getDeleted();
}
@Override
public String getDeletedBy() {
return page.getDeletedBy();
}
@Override
public String getLastModifiedBy() {
return page.getLastModifiedBy();
}
@Override
public Calendar getLastModified() {
return page.getLastModified();
}
@Override
public String getVanityUrl() {
return page.getVanityUrl();
}
@Override
public Tag[] getTags() {
return page.getTags();
}
@Override
public void lock() throws WCMException {
page.lock();
}
@Override
public boolean isLocked() {
return page.isLocked();
}
@Override
public String getLockOwner() {
return page.getLockOwner();
}
@Override
public boolean canUnlock() {
return page.canUnlock();
}
@Override
public void unlock() throws WCMException {
page.unlock();
}
@Override
public Template getTemplate() {
return page.getTemplate();
}
@Override
public Locale getLanguage(boolean b) {
return page.getLanguage(b);
}
@Override
public Locale getLanguage() {
return page.getLanguage();
}
}
}