...
Table of Contents | ||
---|---|---|
|
...
...
Anchor |
---|
...
|
...
|
...
|
...
|
...
|
...
|
Panel | ||||
---|---|---|---|---|
| ||||
The following applies to XperienCentral versions R29 R24.1 and higher. |
To ensure that the Is Used in functionality can detect whether the following content is being used, follow the instructions given.
Custom Elements
Implement the method getReferencedContentItems()
defined in the nl.gx.webmanager.cms.element.Element
interface. Return an array of all content items that are being referenced by the custom element.
Custom Media Items
Implement the method getReferencedContentItems()
defined in the nl.gx.webmanager.cms.mediarepository.MediaItemVersion
interface. Return an array of all content items that are being referenced by the custom media item.
Custom Page Metadata
Implement the method getReferencedContentItems()
defined in the nl.gx.webmanager.cms.core.PageMetaData
interface. Return an array of all content items that are being referenced by the custom page metadata.
HTML |
---|
<br /><br /> |
Panel | ||||
---|---|---|---|---|
| ||||
The following applies to XperienCentral versions 10.22.0 and higher. |
The Is Used In widget shows an overview of content items that are using the currently selected content item. In XperienCentral versions 10.22.0 and earlier, the usage of content items referring to a custom content type was not detected for content items from a custom content type, The widget would only show a count of 0 used content items. The API of several content items in XperienCentral has been extended with a method for implementing this used-in relationship for custom content types. This functionality is available via the new abstract method:
Code Block | ||
---|---|---|
| ||
ContentItem<?>[] getReferencedContentItems(); |
For all custom content items that implement or extend one of the following interfaces and classes:
Element
ElementImpl
MediaItemVersion
MediaItemVersionImpl
TemporaryRichTextInlineElement
The result of this method is the list of used content items (as defined by the projects requirements). The following is a code snippet from a custom content type (extending MediaItemVersion
) which implements the method getReferencedContentItems()
.
Code Block | ||
---|---|---|
| ||
@Override
@Property
public String getReferencedContentIds() {
return JcrUtil.getString(getPrivateNode(), WCBConstants.NAMESPACE_PREFIX + ":referencedcontentids");
}
@Override
public void setReferencedContentIds(String contentids) {
JcrUtil.setString(getPrivateNode(), WCBConstants.NAMESPACE_PREFIX + ":referencedcontentids", contentids);
}
public ContentItem<?>[] getReferencedContentItems() { List<ContentItem<?>> result = new ArrayList<ContentItem<?>>();
if (getReferencedContentIds() != null && !"".equals(getReferencedContentIds())) {
Session session = getSessionManager().getActiveSession();
if (session != null) {
for (String contentid : getReferencedContentIds().split(",")) {
try {
result.add((MediaItem) session.getWrapper(new Integer(contentid).intValue(), MediaItem.class));
} catch (NumberFormatException e) {}
}
}
}
return result.toArray(new ContentItem[result.size()]);
} |
Use in Page Metadata
It is also possible to define this method for custom page metadata. The method must be added to the page metadata class. Additionally, an adapter must be implemented that supplies the result of the method to the indexer service. The following are examples of implementations of both the method definition and the adapter:
Method Implementation
Code Block | ||
---|---|---|
| ||
/**
* Returns the content items that this element refers to.
*
* @return List of referred content items, or <code>null</code> if no content item is referenced.
*/
@ReferField(stored = false, indexed = true, adapter = ContentReferenceFieldAdapter.class) ContentItem<?>[] getReferencedContentItems(); |
Adapter Implementation
Code Block | ||
---|---|---|
| ||
package com.gxwebmanager.helloworld.helloworldpagemetadata.pagemetadata;
import java.util.Collections;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import nl.gx.webmanager.cms.core.RelatedDownloadLink;
import nl.gx.webmanager.cms.core.RelatedInternalLink;
import nl.gx.webmanager.cms.core.RelatedLink;
import nl.gx.webmanager.cms.core.RelatedMediaItemLink;
import nl.gx.webmanager.cms.core.RelatedResourceLink;
import nl.gx.webmanager.cms.mediarepository.MediaItemDownloadVersion;
import nl.gx.webmanager.services.contentdomain.api.ContentDomainException;
import nl.gx.webmanager.services.contentdomain.api.ContentDomainResolver;
import nl.gx.webmanager.services.contentindex.adapter.FieldAdapter;
import nl.gx.webmanager.services.framework.spi.FrameworkException;
import nl.gx.webmanager.services.framework.spi.FrameworkFactory;
/**
* Adapter that takes a content item, and returns a String-reference to it, e.g. page-32423. Logs
* a warning and returns null if the given item could not be resolved.
*
* @see ContentDomainResolver
*/
public class ContentReferenceFieldAdapter implements FieldAdapter<Object> {
private static final Logger LOG = Logger.getLogger(ContentReferenceFieldAdapter.class.getName());
@Override
public boolean isLanguageSpecific() {
return false;
}
@Override
public Object adapt(Object item, Locale forLocale) {
if (item == null) {
return null;
}
if (item instanceof RelatedLink) {
return adaptLinkReference(item, forLocale);
}
return getItemId(item);
}
private String getItemId(Object item) {
try {
ContentDomainResolver resolver = (ContentDomainResolver) FrameworkFactory.getInstance().getFramework().getService(ContentDomainResolver.class.getName());
return resolver.entityToId(item);
} catch (FrameworkException | ContentDomainException e) {
LOG.log(Level.WARNING, "Failed to retrieve content reference for " + item, e);
}
return null;
}
private Object adaptLinkReference(Object link, Locale forLocale) {
if (link instanceof RelatedInternalLink) {
return adapt(((RelatedInternalLink) link).getPage(), forLocale);
} else if (link instanceof RelatedMediaItemLink) {
return adapt(((RelatedMediaItemLink) link).getMediaItem(), forLocale);
} else if (link instanceof RelatedDownloadLink) {
MediaItemDownloadVersion downloadVersion = ((RelatedDownloadLink) link).getInContextDownloadMediaItemDownloadVersion();
if (downloadVersion != null) {
String itemId = getItemId(downloadVersion.getContentItem());
if (itemId != null) {
return Collections.singletonMap("download", itemId);
}
}
} else if (link instanceof RelatedResourceLink) {
return adapt(((RelatedResourceLink) link).getResourceInstance(), forLocale);
}
return null;
}
} |
...
Panel | ||||
---|---|---|---|---|
| ||||
The following applies to XperienCentral versions R24.1 and higher. |
In the wm-addon-monitoring
Git repository there is sample code that shows how to develop your own dashboard plugin. This demo code is located in the wmaxmfdashboardplugindemo
folder. This code (mainly written in Angular Typescript) will, when deployed,show up as a separate tab in the Monitoring Dashboard. You can use this project to get started creating your own plugin(s).
- The main
pom.xml
of the bunde contains all the logic needed to build the Angular code for your plugin. It is a variant on the code that can be found in other bundles that use Angular-based code.
The code in the bundle is split into separate Java and Angular parts:
- The Java part that implements the
XMFDashboardPluginsProvider
interface via the OSGI Activator. - The Angular part that implements an Angular library that can be loaded at runtime.
Java XMFDashboardPluginsProvider
This class implements the getDashboardPlugins()
method that is called to by the monitoring framework on bundle load to determine which dashboard plugin(s) are contained within the bundle and how to load them correctly. The following information about the dashboard plugin has to be supplied here:
jsresource
— The full filename (including path) of the Angular library Javascript resource that is built.exportedModule
— The module name that this library exports as a bootstrap (case-sensitive).routedpath
— The path under which the the Angular router should add the dashboard plugin in the main menu of the Monitoring Dashboard. Note that no conflicting paths are allowed so be sure to use an exclusive name for your plugin.translationPath
— The path where i18n JSON files for the ngx-translate mechanism are located. These translation files can be used for static translations in the tab you add.menuNames
— A set of names for your dashboard plugins, one for each locale you support (typicallyen_US
, andnl_NL
).menuIcon
— The icon to display in the main menu of the Monitoring Dashboard. It is the technical name of the Google material icon to use.
Angular Library
The project for the Angular library that makes up the visual part of the plugin is a standard Angular library that can be created via the Angular CLI (see https://angular.io/guide/creating-libraries).
It consists of
- One module that ensures static translations via ngx-translate can be accessed (in the demo:
demoplugin.module.ts
). - One main component that is rendered by Angular as the content of your added tab in the dashboard (the demoplugin.component in the example).
In the main component you can add new custom indicators.
Generic code for the Monitoring Dashboard is located in the xmfdashboardframework
package (version 1.0.1) which is installed via npm (the package is published on our local Nexus server). When changes in the generic code are required, this should be done in the xmfdashboardframework
package and the build result should be published to NPM with a new version number. Normally this should not be required in order to create a plugin for the Monitoring Dashboard.
Two indicators are added by the example (http-backend-request-multinode-card and clusterinfo-card) which shows you how you could create indicator cards.
All the indicator cards are developed in the Angular Material style for the cards themselves, Angular Flex layout is used to place them on the canvas (see https://material.angular.io/ and https://github.com/angular/flex-layout). Please note since you are developing in an Angular library that is loaded at run-time by the main Monitoring Dashboard panel, you do not have the freedom to import anything from the npm. The main dashboard must be able to resolve the imports required. The following are supported:
'@angular/core' '@angular/common' '@angular/router' '@angular/flex-layout' '@angular/material' '@ngx-translate/core' '@angular/cdk/overlay' '@angular/common/http' 'ngx-cookie-service' 'rxjs' 'rxjs/operators' 'chart.js' 'ng2-charts' '@ngx-translate/http-loader'
'xmfdashboardframework'
Translation files for ngx-translate should be added under the assets folder (in the demo found under project/demoplugin/assets
).
REST Services
The following REST services are offered by the xmfdashboardframework
:
ClusterEventRestService
— Retrieves the available cluster nodes in the installation.IndicatorSetRestService
— Retrieves indicator sets and the measured values in these sets as offered by thexmfframework
.IndicatorSetConfigurationRestService
— Retrieves and updates the configuration parameters of indicator sets as offered by thexmfframework
.LocaleRestService
— Retrieves the current locale in the edit environment.WebsitesRestService
— Retrieves the available websites in the installation.
Components
The following Angular/web-components are offered by the xmfdashboardframework
:
...
...
Developing Your Own Indicators
The explanation above only describes how to create a Monitoring Dashboard plugin but does not cover how to develop your own indicator set(s). That is done entirely in Java. See the wmaxmfindicators
bundle for an example of how to create your own custom indicators. As a starting point you should implement an XMFIndicatorProvider
that enables the registration of your custom indicators. See the file DefaultIndicatorsServiceImpl.java
in wmaxmfindicators
. Refer to the Javadoc for wmaxmfapi
in the wm-addon-monitoring
package for the interfaces offered by the framework.In the wm-addon-monitoring
Git repository there is sample code that shows how to develop your own dashboard plugin. This demo code is located in the wmaxmfdashboardplugindemo
folder. This code (mainly written in Angular Typescript) will, when deployed,show up as a separate tab in the Monitoring Dashboard. You can use this project to get started creating your own plugin(s).
- The main
pom.xml
of the bunde contains all the logic needed to build the Angular code for your plugin. It is a variant on the code that can be found in other bundles that use Angular-based code.
The code in the bundle is split into separate Java and Angular parts:
- The Java part that implements the
XMFDashboardPluginsProvider
interface via the OSGI Activator. - The Angular part that implements an Angular library that can be loaded at runtime.
Java XMFDashboardPluginsProvider
This class implements the getDashboardPlugins()
method that is called to by the monitoring framework on bundle load to determine which dashboard plugin(s) are contained within the bundle and how to load them correctly. The following information about the dashboard plugin has to be supplied here:
jsresource
— The full filename (including path) of the Angular library Javascript resource that is built.exportedModule
— The module name that this library exports as a bootstrap (case-sensitive).routedpath
— The path under which the the Angular router should add the dashboard plugin in the main menu of the Monitoring Dashboard. Note that no conflicting paths are allowed so be sure to use an exclusive name for your plugin.translationPath
— The path where i18n JSON files for the ngx-translate mechanism are located. These translation files can be used for static translations in the tab you add.menuNames
— A set of names for your dashboard plugins, one for each locale you support (typicallyen_US
, andnl_NL
).menuIcon
— The icon to display in the main menu of the Monitoring Dashboard. It is the technical name of the Google material icon to use.
Angular Library
The project for the Angular library that makes up the visual part of the plugin is a standard Angular library that can be created via the Angular CLI (see https://angular.io/guide/creating-libraries).
It consists of
- One module that ensures static translations via ngx-translate can be accessed (in the demo:
demoplugin.module.ts
). - One main component that is rendered by Angular as the content of your added tab in the dashboard (the demoplugin.component in the example).
In the main component you can add new custom indicators.
Generic code for the Monitoring Dashboard is located in the xmfdashboardframework
package (version 1.0.1) which is installed via npm (the package is published on our local Nexus server). When changes in the generic code are required, this should be done in the xmfdashboardframework
package and the build result should be published to NPM with a new version number. Normally this should not be required in order to create a plugin for the Monitoring Dashboard.
Two indicators are added by the example (http-backend-request-multinode-card and clusterinfo-card) which shows you how you could create indicator cards.
All the indicator cards are developed in the Angular Material style for the cards themselves, Angular Flex layout is used to place them on the canvas (see https://material.angular.io/ and https://github.com/angular/flex-layout). Please note since you are developing in an Angular library that is loaded at run-time by the main Monitoring Dashboard panel, you do not have the freedom to import anything from the npm. The main dashboard must be able to resolve the imports required. The following are supported:
'@angular/core' '@angular/common' '@angular/router' '@angular/flex-layout' '@angular/material' '@ngx-translate/core' '@angular/cdk/overlay' '@angular/common/http' 'ngx-cookie-service' 'rxjs' 'rxjs/operators' 'chart.js' 'ng2-charts' '@ngx-translate/http-loader'
'xmfdashboardframework'
Translation files for ngx-translate should be added under the assets folder (in the demo found under project/demoplugin/assets
).
REST Services
The following REST services are offered by the xmfdashboardframework
:
ClusterEventRestService
— Retrieves the available cluster nodes in the installation.IndicatorSetRestService
— Retrieves indicator sets and the measured values in these sets as offered by thexmfframework
.IndicatorSetConfigurationRestService
— Retrieves and updates the configuration parameters of indicator sets as offered by thexmfframework
.LocaleRestService
— Retrieves the current locale in the edit environment.WebsitesRestService
— Retrieves the available websites in the installation.
Components
The following Angular/web-components are offered by the xmfdashboardframework
:
AbstractMultiValueCard
— The base-class that implements a basic pattern for handling indicator dataDoughnutGraphComponent (xmf-doughnut-graph
) — Used to draw a doughnut graphPieGraphComponent
(xmf-pie-graph
) — Used to draw a pie graphIndicatorCardContentComponent (xmf-indicatorcard-content
) —Used as a wrapper for the actual card content with a conforming height and look-and-feelIndicatorCardHeaderComponent
(xmf-indicatorcard-header
) —Used as the default header for a card showing settings and refresh iconsMultiValueCardComponent (xmf-multivalue-card
) — Used to display a default styled card with a row or column of indicatorsMultiValueContentComponent (xmf-multivalue-content
) —Used to display a row or column of indicatorsSingleValueContentComponent
(xmf-singlevalue-content
) —Used to display a single indicators
When developing a new card the following pattern can be followed. This is a class that implements the data layer of the indicator set to be visualized and it extends AbstractMultiValueCard:
<mat-card>
<xmf-indicatorcard-header></xmf-indicatorcard-header>
<xmf-indicatorcard-content>
<Specific content of the card>
</xmf-indicatorcard-content>
</mat-card>
In the wmaxmfdashboard
main dashboard, several examples can be found on how to use the xmfdashboardframework
.
Developing Your Own Indicators
The explanation above only describes how to create a Monitoring Dashboard plugin but does not cover how to develop your own indicator set(s). That is done entirely in Java. See the wmaxmfindicators
bundle for an example of how to create your own custom indicators. As a starting point you should implement an XMFIndicatorProvider
that enables the registration of your custom indicators. See the file DefaultIndicatorsServiceImpl.java
in wmaxmfindicators
. Refer to the Javadoc for wmaxmfapi
in the wm-addon-monitoring
package for the interfaces offered by the framework.
...
Custom Content and the Is Used in Widget
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
The following applies to XperienCentral versions 10.22.0 and higher. |
The Is Used In widget shows an overview of content items that are using the currently selected content item. In XperienCentral versions 10.22.0 and earlier, the usage of content items referring to a custom content type was not detected for content items from a custom content type, The widget would only show a count of 0 used content items. The API of several content items in XperienCentral has been extended with a method for implementing this used-in relationship for custom content types. This functionality is available via the new abstract method:
Code Block | ||
---|---|---|
| ||
ContentItem<?>[] getReferencedContentItems(); |
For all custom content items that implement or extend one of the following interfaces and classes:
Element
ElementImpl
MediaItemVersion
MediaItemVersionImpl
TemporaryRichTextInlineElement
The result of this method is the list of used content items (as defined by the projects requirements). The following is a code snippet from a custom content type (extending MediaItemVersion
) which implements the method getReferencedContentItems()
.
Code Block | ||
---|---|---|
| ||
@Override
@Property
public String getReferencedContentIds() {
return JcrUtil.getString(getPrivateNode(), WCBConstants.NAMESPACE_PREFIX + ":referencedcontentids");
}
@Override
public void setReferencedContentIds(String contentids) {
JcrUtil.setString(getPrivateNode(), WCBConstants.NAMESPACE_PREFIX + ":referencedcontentids", contentids);
}
public ContentItem<?>[] getReferencedContentItems() { List<ContentItem<?>> result = new ArrayList<ContentItem<?>>();
if (getReferencedContentIds() != null && !"".equals(getReferencedContentIds())) {
Session session = getSessionManager().getActiveSession();
if (session != null) {
for (String contentid : getReferencedContentIds().split(",")) {
try {
result.add((MediaItem) session.getWrapper(new Integer(contentid).intValue(), MediaItem.class));
} catch (NumberFormatException e) {}
}
}
}
return result.toArray(new ContentItem[result.size()]);
} |
Use in Page Metadata
It is also possible to define this method for custom page metadata. The method must be added to the page metadata class. Additionally, an adapter must be implemented that supplies the result of the method to the indexer service. The following are examples of implementations of both the method definition and the adapter:
Method Implementation
Code Block | ||
---|---|---|
| ||
/**
* Returns the content items that this element refers to.
*
* @return List of referred content items, or <code>null</code> if no content item is referenced.
*/
@ReferField(stored = false, indexed = true, adapter = ContentReferenceFieldAdapter.class) ContentItem<?>[] getReferencedContentItems(); |
Adapter Implementation
Code Block | ||
---|---|---|
| ||
package com.gxwebmanager.helloworld.helloworldpagemetadata.pagemetadata;
import java.util.Collections;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import nl.gx.webmanager.cms.core.RelatedDownloadLink;
import nl.gx.webmanager.cms.core.RelatedInternalLink;
import nl.gx.webmanager.cms.core.RelatedLink;
import nl.gx.webmanager.cms.core.RelatedMediaItemLink;
import nl.gx.webmanager.cms.core.RelatedResourceLink;
import nl.gx.webmanager.cms.mediarepository.MediaItemDownloadVersion;
import nl.gx.webmanager.services.contentdomain.api.ContentDomainException;
import nl.gx.webmanager.services.contentdomain.api.ContentDomainResolver;
import nl.gx.webmanager.services.contentindex.adapter.FieldAdapter;
import nl.gx.webmanager.services.framework.spi.FrameworkException;
import nl.gx.webmanager.services.framework.spi.FrameworkFactory;
/**
* Adapter that takes a content item, and returns a String-reference to it, e.g. page-32423. Logs
* a warning and returns null if the given item could not be resolved.
*
* @see ContentDomainResolver
*/
public class ContentReferenceFieldAdapter implements FieldAdapter<Object> {
private static final Logger LOG = Logger.getLogger(ContentReferenceFieldAdapter.class.getName());
@Override
public boolean isLanguageSpecific() {
return false;
}
@Override
public Object adapt(Object item, Locale forLocale) {
if (item == null) {
return null;
}
if (item instanceof RelatedLink) {
return adaptLinkReference(item, forLocale);
}
return getItemId(item);
}
private String getItemId(Object item) {
try {
ContentDomainResolver resolver = (ContentDomainResolver) FrameworkFactory.getInstance().getFramework().getService(ContentDomainResolver.class.getName());
return resolver.entityToId(item);
} catch (FrameworkException | ContentDomainException e) {
LOG.log(Level.WARNING, "Failed to retrieve content reference for " + item, e);
}
return null;
}
private Object adaptLinkReference(Object link, Locale forLocale) {
if (link instanceof RelatedInternalLink) {
return adapt(((RelatedInternalLink) link).getPage(), forLocale);
} else if (link instanceof RelatedMediaItemLink) {
return adapt(((RelatedMediaItemLink) link).getMediaItem(), forLocale);
} else if (link instanceof RelatedDownloadLink) {
MediaItemDownloadVersion downloadVersion = ((RelatedDownloadLink) link).getInContextDownloadMediaItemDownloadVersion();
if (downloadVersion != null) {
String itemId = getItemId(downloadVersion.getContentItem());
if (itemId != null) {
return Collections.singletonMap("download", itemId);
}
}
} else if (link instanceof RelatedResourceLink) {
return adapt(((RelatedResourceLink) link).getResourceInstance(), forLocale);
}
return null;
}
} |
...
Developing Custom Bulk Actions
...
In a standard installation, XperienCentral users are managed in the Authorization component. Along with the Authorization component, there are two types of credentials sets that are not targeted at the editorial tasks but are infrastructure-related. By default these credential sets are managed by the following properties in the XperienCentral Setup Tool (General (R30 and older) tab):
These credentials sets are for:
...
This can be accomplished via your own integration component by creating a plugin that implements the Credentials Service Provider. When there is no plugin active that implements the credentials services, a look-up is done on the settings internal_http_use_authentication
or internal_http_use_form_authentication
in the "application_settings" section in the General (R30 and older) tab of the Setup Tool. If a plugin is active that implements the XperienCentral credentials service, the username/password combination from the plugin is used to authorize the user.
...