« Back to Expando

Developing with Expando

This is an article about Expando Development. For information about Expando, see Expando.

Developing with Expando #

Introduction #

Expando attributes can extend objects with custom properties/fields; these additional properties are first class Liferay objects, available for use in constrained searches and so on if desired. For example, imagine we have some form of external content generator, the output of which we wish to programmatically inject into the Liferay WCM/CMS, as doing so allows us to get all of the Liferay Web Content/Journal Article features, (searching RSS etc etc). Our piece of content (Journal Article) could represent an employment/job advert. It will be composed of text, the usual metadata (date of posting etc) and some other metadata items, including location of the job. We would like to store this Location metadata with the JournalArticle representing the job advert and make it searchable. Ultimately, from any search box we want to be able to give a search query such as:

Location: Brisbane

and get the right search results. We can do this by extending JournalArticle objects with a new Location Expando attribute.

Technique #

  1. Create/Commit the new Job Advert JournalArticle into Liferay by using the JournalArticleLocalServiceUtil.addArticle or similar method.
  2. Create an Expando Table for your content class (making one if required) - the example below uses the default table.
  3. For each new field/data item you want persisted and searchable, create a new ExpandoColumn in your Expando table of the correct type.
    1. the types are ints - itemized as constants in com.liferay.portlet.expando.model.ExpandoColumnConstants
    2. If you want the new property to be searchable it must be a String type
  4. For your job advert JournalArticle, get it's ExpandoBridge object, and add an Attribute Property of indexable (set to true or false as required).
  5. Add the altered properties back to the Expando Column.
  6. Use ExpandoValueLocalServiceUtil to add the new value (for example Brisbane) to the ExpandoColumn (Location), on the ExpandoTable.
  7. If required call the indexer to be run on your content.
  8. Ensure it worked - browse the RDBMS and index, or go to a search box and try a search on your new property.

Code Example #

  • Method Call:
		Assert.notNull(myJournalArticle,
				"Journal Article creation failed - returned null");
		// Set ExpandoAttributes
		try {
			setExpandoAttributesAndValues(teamsiteDocument.getExpando(),
					myJournalArticle.getCompanyId(), myJournalArticle.getResourcePrimKey(),
					JournalArticle.class, myJournalArticle.getExpandoBridge(),
					myJournalArticle.isIndexable());
		} catch (PortalException e) {
			logger.error("unable to set ExpandoAttributes on JournalArticle:"
					+ teamsiteDocument.getUuid() + " title:", e);
		}
  • Set the attributes: (note that the class ExpandoItem below is just a key value pair object like Map.Entry)
void setExpandoAttributesAndValues(
			Set<ExpandoItem> incomingExpandoSet, long companyId,
			long classPKId, Class klass, ExpandoBridge expandoBridge, boolean indexable)
			throws PortalException, SystemException {
		ExpandoTable tbl = null;
		CompanyThreadLocal.setCompanyId(companyId);
		try {
			tbl = ExpandoTableLocalServiceUtil.getDefaultTable(klass.getName());
		} catch (NoSuchTableException e) {
			tbl = ExpandoTableLocalServiceUtil.addDefaultTable(klass.getName());
		} finally {
			if (tbl == null) {
				throw new SystemException("Could not get/create expando table");
			}
		}

		for (ExpandoItem item : incomingExpandoSet) {
			String itemName = item.getName();
			int itemType = item.getType();

			ExpandoColumn col = ExpandoColumnLocalServiceUtil.getColumn(tbl
					.getTableId(), itemName);

			if (null == col) {
				col = ExpandoColumnLocalServiceUtil.addColumn(tbl.getTableId(),
						itemName, itemType);

			}
			UnicodeProperties properties = expandoBridge
					.getAttributeProperties(col.getName());
			properties.setProperty(ExpandoBridgeIndexer.INDEXABLE, Boolean.valueOf(indexable)
					.toString());
			col.setTypeSettingsProperties(properties);

			ExpandoValue val = null;
			if (item.isArray()) {
				Serializable[] itemValue = (Serializable[]) item
						.getArrayValue();
				val = ExpandoValueLocalServiceUtil.addValue(klass.getName(),
						tbl.getName(), col.getName(), classPKId, itemValue);

			} else {
				Serializable itemValue = (Serializable) item.getValue();
				val = ExpandoValueLocalServiceUtil.addValue(klass.getName(),
						tbl.getName(), col.getName(), classPKId, itemValue);
			}
			if (val == null) {
				throw new SystemException(
						"Could not add expando value: class: "
								+ klass.getName() + ", table: " + tbl.getName()
								+ ", column: " + col.getName() + " classPKId: "
								+ classPKId);
			}
			
			
		}
		
		reIndex(indexable, klass.getName(), classPKId);
	}

	/**
	 * Reindex the journal article
	 * @param isIndexEnabled (for the journal article)
	 * @param className
	 * @param classPK
	 */
	void reIndex(boolean isIndexEnabled, String className, long classPK) {
		if (!isIndexEnabled) {
			return;
		}
		Indexer indexer = IndexerRegistryUtil.getIndexer(className);
		if (indexer != null) {
			try {
				indexer.reIndex(className, classPK);
			} catch (Exception e) {
				logger.error("reindex journal article error", e);
			}
		}
	}

Resources #

  1. Liferay 5.2.2 uses Lucene version 2.3.2 - The (very powerful) query syntax for this version is documented here: http://lucene.apache.org/java/2_3_2/queryparsersyntax.html
  2. Lucene index browser Luke - http://www.getopt.org/luke/ start the Java webstart version (JNLP) and browse to your Liferay Lucene index at ${LIFERAYHOME}\liferay-portal-5.2.2\data\lucene\${COMPANY_ID}
  3. Relevant Javadoc:
    1. http://docs.liferay.com/portal/5.2/javadocs/portal-service/com/liferay/portlet/journal/service/JournalArticleLocalServiceUtil.html
    2. http://docs.liferay.com/portal/5.2/javadocs/portal-service/com/liferay/portlet/expando/service/ExpandoColumnLocalServiceUtil.html
    3. http://docs.liferay.com/portal/5.2/javadocs/portal-service/com/liferay/portlet/expando/service/ExpandoRowLocalServiceUtil.html
    4. http://docs.liferay.com/portal/5.2/javadocs/portal-service/com/liferay/portlet/expando/service/ExpandoTableLocalServiceUtil.html
    5. http://docs.liferay.com/portal/5.2/javadocs/portal-service/com/liferay/portlet/expando/service/ExpandoValueLocalServiceUtil.html
  4. Another example: Adding an custom attribute to a Community
0 Attachments
62432 Views
Average (5 Votes)
The average rating is 3.8 stars out of 5.
Comments