Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Anchor
top
top
This section explains other topics that are useful for developers working with XperienCentral.

In This Section

Table of Contents
maxLevel2

...

Property Editors

Property Editors are used to facilitate conversions between a complex type and String. Posted values from a HTML form will usually be converted to a String by the servlet engine. Spring MVC offers a way to convert incoming Strings to complex types; it also converts complex types to Strings when the response is sent back to the browser. Spring MVC offers this functionality through the Property Editors. The Spring MVC and the XperienCentral platforms already have a few default Property Editors for the next types:

...

In the following sections, an example of a custom Property Editor is shown based on the Calendar type. By default, there is no support for a property of type Calendar although it might be of interest for plugin developers.

Implement the Custom Property Editor

To implement a custom Property Editor, a class is needed that:

...

Code Block
themeEclipse
public class CustomCalendarEditor extends PropertyEditorSupport {
	private final DateFormat myDateFormat;
	private final static Logger LOG =
Logger.getLogger(CustomCalendarEditor.class.getName());

	public CustomCalendarEditor(DateFormat dateFormat) {
		myDateFormat = dateFormat;
	}
	public void setAsText(String text) {
		if (text == null) {
			setValue(null);
		} else {
			try {
				myDateFormat.parse(text);
				setValue(myDateFormat.getCalendar());
			} catch (ParseException ex) {
				LOG.log(Level.WARNING, "Could not parse the date '" + text + "'" + "\nThe exception\n: " + ex);
			}
		}
	}

	public String getAsText() {
		Calendar value = (Calendar) getValue();
		if (value == null) {
			return "";
		} else {
			return myDateFormat.format(value.getTime());
		}
	}
}

Register the Custom Property Editor

Now that the custom Property Editor is implemented, it has to be registered with Spring MVC. This is done in the initBinder method; this method is placed in the controller of your component (for example, CustomElementController.java). The registration looks like this:

...

Code Block
themeEclipse
@Override
public void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
super.initBinder(request, binder);
if (myValidator == null) {
		myValidator = new CustomCalendarEditor(
new SimpleDateFormat("dd/MM/yyyy");
addValidator(myValidator);
}
}

The Custom Property Editor in Action

Once the custom Property Editor has been created and registered, it is ready to use. This means that it is now possible to use the Calendar type for properties in the Java code. Below are some code snippets that illustrate the use of the custom the Calendar type Property Editor that was created in the above example.

...

The result as seen in XperienCentral:

 

 

 

Back to Top

 

...

Validators

Validators can be used to validate user input and to generate client side error messages when invalid input is provided by a user. Validators prevent users from entering invalid data. Validators are Java classes that implement the org.springframework.validation.Validator interface. This interface provides two methods:

...

As a result the message “Text may not be empty” will be displayed if the user input was invalid:

 

 

Back to Top

 

...

HTTP Client


The java.net package part of the Java 1.6 API provides a basic set of classes which can be used to handle HTTP GET and POST requests. However, in some cases a more powerful HTTP client API is needed. The commons HTTP client (org.apache.commons.httpclient.HttpClient) may be a better alternative for those cases. This section describes how to use the commons HTTP client in a plugin.

...

Code Block
themeEclipse
private static void configureHttpClient2Proxy(HttpClient httpClient, HttpMethod method) {
	String proxyHost = System.getProperty("http.proxyHost");
	if (proxyHost == null || "".equals(proxyHost)) {
		return;
	}
	try {
		org.apache.commons.httpclient.URI apacheUri = method.getURI();
		java.net.URI javaUri = null;
		if (apacheUri.isAbsoluteURI()==false) {
			javaUri = new 
			java.net.URI(httpClient.getHostConfiguration().getHostURL());
	} else {
		javaUri = new java.net.URI(apacheUri.toString());
	}
	// ProxySelector
	List<Proxy> selectedProxy = 
	ProxySelector.getDefault().select(javaUri);
	if (selectedProxy.size()==0 || 
	selectedProxy.get(0).type()==Proxy.Type.DIRECT) {
		// No proxy needed.
		return;
	}
	HostConfiguration hc = httpClient.getHostConfiguration();
	hc.setHost(javaUri.getHost(), javaUri.getPort(), 
	Protocol.getProtocol(javaUri.getScheme()));
	Proxy proxy = selectedProxy.get(0);
	InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
	hc.setProxy(proxyAddress.getHostName(),proxyAddress.getPort());
	if (System.getProperty("http.proxyUserName") != null) {
		httpClient.getState().setProxyCredentials(null, null,
			new UsernamePasswordCredentials(System.getProperty("http.proxyUserName"), System.getProperty("http.proxyPassword")));
		httpClient.getState().setAuthenticationPreemptive(true);
	}


  } catch (URISyntaxException ex) {
		LOG.log(Level.WARNING, null, ex);
  } catch (URIException ex) {
		lOG.log(Level.WARNING, null, ex);
  }
}

 

Back to Top

 

...

 Adding Custom Indicators to the Performance Dashboard

The XperienCentral Performance Dashboard provides detailed information about how the parts of XperienCentral's infrastructure are functioning. The Performance Dashboard measures the speed and response time of page requests and internal queries as well as other settings that affect how XperienCentral is performing and rates the results according to the optimal expected results. The Performance Dashboard plugin is extensible, which allows you to create plugins that add custom performance indicators. Any custom indicators you create appear on a special tab named “Custom System Performance Indicators”.

...

Code Block
themeEclipse
public class CustomServiceImpl extends SimpleServiceComponent implements SystemHealthIndicatorExtensionPoint {
	// Private logger for this class
	private static final Logger LOG = Logger.getLogger(CustomServiceImpl.class.getName());
	public SystemHealthIndicator[] getPerformanceIndicators() {
	return new SystemHealthIndicator[] {new CustomPI()};
	}

	class CustomPI implements SystemHealthIndicator{
		public String getId() {return "testPI";};
		public String getCategory() {return "my category";}
		public String getType() {return TYPE_CUSTOM;};
		public String getName(Language language) {return "test custom PI";}
		public Object getValue() {return myCache.getCacheRatio;}
		public ValueStatus getValueState() {return myValueStatus;}
		public String getMessage(Language language) {return "test custom PI";}
		public void reset() {}
	}
}

 

Back to Top

 

...

Creating an Extension for the User Profiles Component

The XperienCentral component User Profiles can be extended via the API in order to add custom fields and tabs to the default user profile information. In addition to adding extensions to the user profile information, you can also manage users, groups, newsletter subscriptions, permissions, and banned and reserved words via the XperienCentral API. This makes it possible to enhance the functionality contained within the user profile component for your particular implementation. All data in custom fields and tabs can also be exported together with data in the default user detail fields using the provided export functionality in the User Profiles component.

...

  • nl.gx.webmanager.services.defaultprofileprovider - Contains the interfaces for managing user profile data in the default user profile as provided by XperienCentral.
  • nl.gx.product.wmpuserprofiles.api -  Contains the interfaces for managing custom sub-tabs and permissions for the ‘User Profilescomponent.
  • nl.gx.webmanager.services.usermanager - Contains the interfaces for managing users, groups, and newsletter subscriptions.
  • nl.gx.webmanager.services.usermanager.settings - Contains one interface for managing reserved and banned words.

Generating the Sample Profile Extension Plugin from the User Profiles Archetype

Included with XperienCentral is a sample plugin that extends the user profiles functionality by adding a field to the [User Details] tab (view extension) as well as a new tab named [MSN Details] with one field. By generating a sample profile extension plugin from the archetype, you can see a working example of how extra fields and tabs can be added to the default user profile as well as how the extra data can be exported.

...

As a result, the following folder structure is created containing the source code for the customprofile sample plugin:

 

 

UserManagement Interface Methods

In order to create a custom extension for the user profiles functionality, you must use the following XperienCentral API methods to implement the Profile Extension Provider interface. The following code is taken from the file ProfileExtensionProvider.java:

...

Code Block
themeEclipse
public final class CustomProfileProviderImpl extends SimpleProfileProviderComponent implements
	CustomProfileProvider {

Custom Profile Declarations

In the file src\main\java\nl\gx\product\customprofile\profileprovider\CustomProfileImpl.java, the following code implements the custom profile and initializes the new fields:

...

Code Block
themeEclipse
/**
	* {@inheritDoc}
	*/
	public void setMsnAddress(String newMsnAddress) {
		myMsnAddress = newMsnAddress;
	}

	/**
	* {@inheritDoc}
	*/
	public String getMsnAddress() {
		return myMsnAddress;
	}

	/**
	* {@inheritDoc}
	*/
	public void setIcqAddress(String newIcqAddress) {
		myIcqAddress = newIcqAddress;
	}

	/**
	* {@inheritDoc}
	*/
	public String getIcqAddress() {
	return myIcqAddress;

 

Adding a Custom Tab to the User Profiles Component

The following code shows how to add a custom tab to ‘User Profiles’ component. The code is taken from the file src\main\java\nl\gx\product\customprofile\subtab\CustomSubTab.java:

...

Code Block
themeEclipse
<%@ page language="java" session="false" buffer="none" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/taglib/spring" %>
<%@ taglib prefix="wmedit" uri="http://www.gx.nl/taglib/wmedit"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>

<fieldset>

	<div class="wm_style">
		<table class="widgetgrid">
			<tr>
				<td class="label_left"><fmt:message key="nl.gx.product.customprofile.subtab.msnaddress"/>:</td>
				<td class="datefield"><wmedit:input path="msnAddress" size="25" /></td>
			</tr>
		</table>
	</div>
</fieldset>

 

Adding a Custom Field to the User Details Tab

Custom data fields can be added to the [User Details] tab in order to extend the detailed information you want to store for each user. The following sample code, taken from the file src\main\java\nl\gx\product\customprofile\profileprovider\impl\CustomProfileImpl.java, shows how to add a new field, "ICQ Address" to the [User Details] tab. 

...

Code Block
themeEclipse
%@ page language="java" session="false" buffer="none" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/taglib/spring" %>
<%@ taglib prefix="wmedit" uri="http://www.gx.nl/taglib/wmedit" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %>

<tr>
	<td class="label_left"><fmt:message key="nl.gx.product.customprofile.profileview.icqaddress"/>:</td>
	<td class="datefield"><wmedit:input path="icqAddress" size="20" /></td>
</tr>

 

Exporting Data from Custom Fields

In order for XperienCentral to be able to export data from custom fields, you must declare the new headers that need to be retrieved during the export. For example:

...

This implementation comes from the CustomProfileProviderImpl interface. The methods are part of the ProfileExtensionProvider interface.

 

Back to Top

 

...

Creating Workflow Action Constraints

A workflow action constraint puts a restriction on the transition from one state to another for content items in a workflow. The constraint is based on a specified property or condition belonging to a content item. For example, a constraint can prevent a content item from transitioning from the "Planned" to the "Published" state if it does not have a title or if it does not have an expiration date assigned to it. A constraint can be global and apply to all content types or you can select the specific content type to which it applies.

...

Code Block
themeEclipse
public class TitleWorkflowActionConstraint extends SimpleServiceComponent implements WorkflowActionConstraint {

	private static final Logger LOG = Logger.getLogger(TitleWorkflowActionConstraint.class.getName());

	private static final String TITLEKEY = "pagemetadata.constraint.title";

	private static final Map<Locale, String> TITLE_MESSAGES = new HashMap<Locale, String>();

	private static final Map<Locale, String> VALIDATION_MESSAGES = new HashMap<Locale, String>();

	static {
		Locale localeNL = new Locale("nl", "NL"); 
		ResourceBundle bundle_nl = ResourceBundle.getBundle("messages/messages", new Locale("nl", "NL"));
		ResourceBundle bundle_en = ResourceBundle.getBundle("messages/messages", Locale.US);

		TITLE_MESSAGES.put(localeNL, bundle_nl.getString(TITLEKEY));
		TITLE_MESSAGES.put(Locale.US, bundle_en.getString(TITLEKEY));

		VALIDATION_MESSAGES.put(localeNL, bundle_nl.getString(TITLEKEY));
		VALIDATION_MESSAGES.put(Locale.US, bundle_en.getString(TITLEKEY));
	}

	@Override
	public Map<Locale, String> getTitleMessages() {
		return TITLE_MESSAGES;
	}

@Override
	public String getIdentifier() {
		return WCBConstants.BUNDLE_ID + ".titleWorkflowActionConstraint";
	}

	@Override
	public WorkflowActionConstraintResult validate(final WorkflowEnabled workflowEnabled) {
		final boolean isValid;

		// Validate
		final String title;
		if (workflowEnabled instanceof PageVersion) {
			title = ((PageVersion) workflowEnabled).getTitle();
		} else if (workflowEnabled instanceof MediaItemVersion) {
			title = ((MediaItemVersion) workflowEnabled).getTitle();
		} else {
			title = null;
		}

		isValid = !"".equals(title);
		return new WorkflowActionConstraintResult() {

			@Override
				public String getIdentifier() {
					return TitleWorkflowActionConstraint.this.getIdentifier();
			}

			@Override
			public Map<Locale, String> getMessages() {
				if (isValid) {
					return null;
				} else {
					return VALIDATION_MESSAGES;
				}
			}

			@Override
			public boolean isValid() {
				return isValid;
			}
		}
	}

 

 

Back to Top