Perficient Portal Solutions Blog

Subscribe to RSS feed

Archives

Follow our Portals and Social Business board on Pinterest

Posts Tagged ‘maven’

Using WPS style Resource Environment Providers with Spring

Lee Burch, one of our extremely talented architects, gave me a writeup on “Using WPS style Resource Environment Providers with Spring”  He wanted to know where to post something like this and of course, my first thought is this blog.  His justification for posting this is that while it’s a common use case in the WebSphere Portal world, many developers get it wrong.  So thanks to Lee for the post.

Generally a problem most projects face is how to handle configuration information that varies between environments.  Many times you can handle this by using one of WAS built in resources such as a SMTP server or a JDBC connection pool.  However many times the configuration data won’t fit one of these existing WAS resource types, such as an e-mail address, a server name or a URL.  To solve this a lot of approaches are available some use build tools such as Maven to build different EAR files, others use properties files located outside of the EAR.  Unfortunately both of these solutions have their issues and can be difficult to manage.

To solve this problem WAS provides and WPS leverages the resource environment providers. These allow you to specify your settings as a part of the WAS console at the Cell, Node or Server level.  This provides an easy way to maintain values across many servers while also doing away with the need to have special EARs built for each environment.

The following IBM article discusses this

http://www.ibm.com/developerworks/websphere/library/techarticles/0611_totapally/0611_totapally.html

Unfortunately it requires deployment to the App Server lib/ext directory, something that is not always so easily done particularly in a shared enterprise environment.

However WPS uses Resource Environment Providers but does so differently than the above article specifies, it uses the “Custom Properties” of the resource environment provider and requires no deployment to the App Server, an ideal solution.

While it is possible to bind your code directly to the fetches to the Resource Environment Provider I find a more flexible and much more modern way of addressing the problem is to use Spring and its facility for PropertyPlaceholderConfigurer.

This allows for a Spring config something like this

Read the rest of this post »

Maven and WebSphere Web Applications (Part 2)

The parent project of the multiple module web application uses the uses the <packaging>pom</packaging> tag and several <module> tags to indicate that it is controlling the build order of several artifacts. The control is provided through the reactor plugin.

The file structure that I use is:

    /ear
    /ear/pom.xml
    /web
    /web/pom.xml
.classpath
.project
pom.xml

The ear directory is empty  (except for pom.xml). The application.xml required for an EAR is generated by the was6 maven plugin. The directory structure of the web directory is not shown here but specified as the maven standard directory layout.

There are several fields in the various hidden control structures that must be internally consistent for the build and deploy to work. This is why I prefer to use a maven archetype (created yourself for your project team) project to generate web application projects from scratch. My experience in the field indicates that developers who copy and paste from existing projects often make mistakes which are very hard to diagnose.

These are the items that you need to address:

  • Provide unique namespace (groupId + artifactId) for ear and war modules that is predictable. I solve this by using parent groupId appended with .war or .ear for the child projects.
  • Ensure the parent/child relationship of the three pom.xml files through dependencies and parent references including the correct generated ids.
  • Ensure ibm-web-ext.xml and ibm-web-bnd.xml are included in the web module.
  • Ensure the .project and .classpath files include the correct RAD facets and library definitions for a maven project.
  • Ensure the parent pom.xml has a parent reference to a project that defines the required WAS dependencies (for proper compilation).

Maven and WebSphere Web Applications (Part 1)

Web Applications are WAR files that include java code and JSP files with a web.xml deployment descriptor that are intended to implement dynamic web functionality (as opposed to static web functionality which uses HTML files).

A portal team typically uses this packaging technique for the following artifacts:

  • Portal themes and skins
  • web services
  • iWidgets

WebSphere Approach for Web Applications

The WebSphere Application server only understands EAR files. EAR files are collections of WAR and JAR files with an application.xml deployment descriptor. Developers that come from a Tomcat or JBoss (or similar J2EE application server) background may be accustomed to performing a hot deploy that simply involves them placing a WAR or EAR file in a specific directory. The WebSphere deployment is more involved because of clustering and vendor extensions that provide more robust enterprise features.

Now let’s assume you are creating a Spring web service implementation for your business logic. RAD automatically creates an associated EAR project for your WAR project when you choose dynamic web application during the project creation wizard. The EAR file is deployed on the WebSphere_Portal server instance of the WebSphere Application Server that includes your portal application.

The EAR file can be placed on the server using several techniques:

  • administrative console (via the GUI)
  • wsadmin
  • RAD menus that add project to a local server configuration (technique used by many developers during coding/debugging)

The wsadmin approach is the obvious choice for scripting releases. The administrative console approach is a multiple screen wizard that forces developers to choose values for many vendor extensions and security configurations that are typically beyond the domain knowledge of a component developer.

Maven Approach for Web Applications

A best practice of maven is to follow the one artifact for each pom.xml convention. We have already seen that WebSphere expects an EAR file that contains a WAR file for a typical web application. The solution for this problem is to create a multiple module maven project that serves as the parent for the WAR and EAR files that are required.

The deployment of the EAR file is handled by the was6 maven plugin from codehaus. This plugin will require that your Continuous Integration (CI) server handling the deployments has a WebSphere Application Server installation on the same machine. This is required because the was6 plugin is a wrapper for the wsadmin client (which includes an IBM component that handles the secured communications with a remote WAS instance). The configuration of the was6 maven plugin always requires specifying a -DwasHome property value that points to the root of the WAS server installation. I am not aware of any set of JAR files that implement this functionality (unlike the xmlaccess tool discussed in my WebSphere Portal and Maven post that can be implemented by including jars as dependencies of your custom plugin).

Next up I will discuss the file structure of the project used for my proposed solution for web applications.

Next up: Maven and WebSphere Web Applications (Part 2)

WebSphere Portal and Maven (Part 6)

You use a parent pom.xml file that each portlet project inherits from to encapsulate your dependencies and maven plugin bindings. This keeps all this code out of sight from your portlet project.

This first code posting shows the plugin definition under a pluginManagement section. This section is used to create any dependencies used by the plugin itself:

...
<pluginManagement>
	<plugins>
		<plugin>
			<groupId>com.mycompany</groupId>
			<artifactId>portlet-deploy</artifactId>
			<version>1.0.0-SNAPSHOT</version>
			<dependencies>
				<!-- Needed for ANT scp task -->
				<dependency>
					<groupId>org.apache.ant</groupId>
					<artifactId>ant-jsch</artifactId>
					<version>1.7.1</version>
				</dependency>
				<!-- Needed for propertyregexp task -->
				<dependency>
					<groupId>ant-contrib</groupId>
					<artifactId>ant-contrib</artifactId>
					<version>1.0b3</version>
				</dependency>
				<dependency>
					<groupId>ant</groupId>
					<artifactId>ant-optional</artifactId>
					<version>1.5.3-1</version>
				</dependency>
				<!-- END: Needed for propertyregexp task -->
				<!-- For XSLT transformations -->
				<dependency>
					<groupId>ant</groupId>

Read the rest of this post »

WebSphere Portal and Maven (Part 5)

I recommend using a maven plugin to package your logic. The reason is that the ANT antcall and XSLT tasks require file inputs (and do not support URIs). When you package these file resources into a jar (as you do with a plugin) then you can extract them to the correct relative filesystem locations as part of your mojo startup code. That means you don’t require developers to place these files into the projects themselves. This also means that you control the distribution of these key files and can replace them all at once in a new maven plugin version without having to email everyone that uses your artifacts.

The following source code example represents a java class that performs the setup and execution of your deployment logic:

Read the rest of this post »

WebSphere Portal and Maven (Part 4)

So far you have a compiled portlet and an XSLT capable of producing an xmlaccess request input file based on your specific portlet.xml file.

Next you create an ANT script that is capable of submitting your request to the portal server. The script presented below diverges to distinguish between local portlet deployments (when you are deploying to a portal server on the same machine on which you are building) and remote portlet deployments (when you are deploying to a remote portal server). The divergence is because local portlet deployments do not require any copying of the generated WAR file. For remote deployments I use the ANT scp task to copy the WAR file to the remote machine.

I prefer the scp task because you can place the file into the ${wp_profile}/installableApps directory (which follows standard IBM practice). This method requires that you have a shell account on the remote machine with correct write privileges. I’ll admit that I have used the nexus/archiva snapshot repository URL as an input to the xmlaccess request when I didn’t have a shell account. This hack avoids the copying procedure, but I would avoid this method when possible because the logic to predict the URL is not as robust. You can plug any type of remote copying or URL based sharing method into this portion of the script.

The name of your web module in the wps admin console will default to ${artifactId}-${version}.war because that is derived from the filename of the deployed WAR file. Adjusting this would require some deeper level maven hacks that I like to avoid. However, the name of your web module in the AppServer admin console is under your control. I like to use ${MyCompany}_ as a prefix so that all your projects can be quickly filtered to distinguish them from the existing IBM modules.

Here is the ANT script:

<project default="install.local">
	<target name="install.local" depends="private.local.init, private.deploy" />
	<target name="install.remote" depends="private.remote.init, private.deploy" />

	<target name="private.local.init">
		<property name="file.url" value="file:///${basedir}/${project.artifactId}-${project.version}.war" />
	</target>

	<target name="private.deploy">
		<!-- Step 1: Generate xmlaccess input from portlet.xml -->
		<echo message="Step 1: Generate xmlaccess request: target/deployme.xml" />
		<xslt in="../WebContent/WEB-INF/portlet.xml" out="deployme.xml" force="true" style="xmlaccess-input.xsl">
			<param name="WAR_URL" expression="${file.url}" />
			<param name="DISPLAY_NAME" expression="MyCompany_${project.artifactId}" />
		</xslt>

		<!-- Step 2: Run the install/update xmlaccess script -->
		<!-- If the java process is forked then the CLASSPATH must be set  -->
		<echo message="Step 2: Deploying portlet using xmlaccess input: target/deployme.xml" />
		<java classname="com.ibm.wps.xmlaccess.XmlAccess" logError="true" resultproperty="xmlaccessReturnCode">
			<arg line="-in target/deployme.xml" />
			<arg line="-user ${wpsuser}" />
			<arg line="-password ${wpspassword}" />
			<arg line="-url http://${wpshost}:${wpsport}/${wpscontext}/config" />
			<arg line="-out target/output.xml" />
		</java>

		<!-- Step 3: Determine result of deployment attempt -->
		<echo message="Step 3: Determine script result..." />
		<taskdef resource="net/sf/antcontrib/antlib.xml" />
		<if>
			<not>
				<equals arg1="${xmlaccessReturnCode}" arg2="0" />
			</not>
			<then>
				<length property="fileLength" file="output.xml" />
				<loadfile property="output.result" srcFile="output.xml" />
				<condition property="output.result" value="output.xml is empty">
					<equals arg1="${fileLength}" arg2="0" />
				</condition>
				<echo message="----- output.xml starts -----" />
				<echo>${output.result}</echo>
				<echo message="----- output.xml ends ----/apps/IBM/Profiles-" />
				<fail message="Execution of deployme.xml Failed">
					<condition>
						<not>
							<equals arg1="${xmlaccessReturnCode}" arg2="0" />
						</not>
					</condition>
				</fail>
			</then>
			<else>
				<echo message="Execution of deployme.xml OK" />
			</else>
		</if>
	</target>

	<!--Use SCP to copy the WAR file to the remote machine -->
	<target name="private.remote.init">
		<scp file="${project.artifactId}-${project.version}.war" todir="${scpuser}@${wpshost}:${remotedir}" password="${scppassword}" trust="true" />
		<property name="file.url" value="file:///${remotedir}/${project.artifactId}-${project.version}.war" />
	</target>
</project>

The next post in the series will explain how the XSLT and and the ANT code is combined in a maven plugin to perform your portlet deployment.

Next up: WebSphere Portal and Maven (Part 5)

 

WebSphere Portal and Maven (Part 3)

The deployment of a portlet to a portal server is accomplished using xmlaccess (also called the XML configuration interface). At this point I need to point out that the deploy goal of maven is a separate concept from a portlet deployment. The maven deploy goal is intended to move your packaged maven artifact to the maven repository server. A portlet deployment means that you are moving and installing your portlet onto a portal server where it can be placed onto a page and receive requests.

You actually perform your portlet deployment during the pre-integeration-test phase of the maven lifecycle. This is done here instead of the deploy phase because you would not want to share the code with other developers if your integration tests fail during the integration-test phase.

The input file of an xmlaccess request is an XML configuration file with specialized syntax to describe your intended operation. You want to modify the DeployPortlet.xml sample file included in your portal installation and replace it with parameters that match the portlet you wish to deploy.

I have created an XSLT file that can process the portlet.xml descriptor and produce a valid xml configuration file that you can send in an xmlaccess request. Readers should notice that this is a modified form of the DeployPortlet.xml sample file included with the portal. In a future post I will describe how and where this file gets executed during the build.

<?xml version="1.0"?>
<xsl:stylesheet
	version="2.0"
	exclude-result-prefixes='wps'
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:wps="http://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">	

<xsl:output method="xml" indent="yes"/>
<xsl:param name="WAR_URL"/>
<xsl:param name="DISPLAY_NAME"/>

<xsl:template match="/">
	<xsl:comment>Generated version: 1.0</xsl:comment>
	<request 
		type="update"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:noNamespaceSchemaLocation="PortalConfig_7.0.0.xsd">
		<portal action="locate">
			<xsl:apply-templates/>
		</portal>
	</request>
</xsl:template>

<xsl:template match="wps:portlet-app">
	<web-app action="update" active="true" uid="{@id}.webmod">
		<url><xsl:value-of select="$WAR_URL"/></url>
		<!-- Use the maven artifactId as the display name in the WAS console with a prefix to group together -->
		<display-name><xsl:value-of select="$DISPLAY_NAME"/></display-name>
		<servlet action="update" referenceid="{wps:portlet/wps:portlet-name}.servlet"/>
		<portlet-app action="update" uid="{@id}">
            <xsl:apply-templates select="wps:portlet"/>
        </portlet-app>
	</web-app>
</xsl:template>

<xsl:template match="wps:portlet">
	<portlet action="update" name="{wps:portlet-name}" />
</xsl:template>

</xsl:stylesheet>

Next up: WebSphere Portal and Maven (Part 4)

WebSphere Portal and Maven (Part 2)

This post assumes that you have installed an automated build stack (which consists of maven, a maven compatible repository server, and a continuous integration (CI) server). This post also assumes that you have installed and configured the m2eclipse plugin for your RAD/Eclipse IDE. The details of these installations are beyond the scope of this series of posts.

A maven repository is software (like archiva or nexus) that stores your dependencies in a single remote server. Corporate development shops often choose to maintain an internal repository server which mirrors the maven central repository. The internal repository offers greater control, security, and faster internal downloads. IBM does not publish the portal dependencies to the maven central repository. (You will find that the majority of open sources projects will publish to maven central).

Since IBM does not publish the portlet dependencies you need an internal repository for compiling portlets (unless you use the system dependency scope and a private repository, but I don’t think this approach is as maintainable in a team development setting.)

So what are your dependencies?

I have taken two approaches for figuring this out:

  1. Go into RAD and find the Project Build Path and examine the WebSphere Portal v7.0 library definition and copy all the jar names and locations. Upload all these files to your internal server. List all these files as provided scope dependencies in your project. I’ll admit I have done this before figuring out the next method.
  2. Locate the ${PortalServer}/doc/compile/portletapi_20.jar file and list this as a provided scope dependency.

What is the difference between these methods?

If I developed any bizarre classpath issues (like NoSuchMethodError) I would revert to the first method to ensure I was replicating the RAD wizard exactly.

You use the provided scope of maven because you want to compile your code using the jar but the actual implementation jars are provided by the portal server when you deploy the code to a running portal server. The following command deploys your dependency to a remote maven repository:

mvn deploy:deploy-file -DgroupId=com.ibm.portal -DartifactId=portletapi20 -Dversion=7.0 -Dpackaging=jar -Dfile=portletapi_20.jar -DrepositoryId=${repnamehere} -Durl=${repurlhere}

You should note that all these parameter values were items thought up by you. I find that using artifactId=${name}.jar without the jar extension and using a version number to correspond to your WebSphere Portal Server (WPS) version help maintain the logical link between these jars and their source. Finally ${repnamehere} and ${repurlhere} are values that make sense at your organization.

I always create a parent maven project of type pom that each portlet project inherits from (the reasons for this will become clearer in future posts). This parent project links the dependency as:

<dependency>

<groupId>com.ibm.portal</groupId>

<artifactId>portletapi_20</artifactId>

<version>7.0</version>

<scope>provided</scope>

</dependency>

At this point your portlet project can compile and will be packaged as a WAR file suitable for deployment on your portal server.

Next up: WebSphere Portal and Maven (Part 3)

 

 

 

WebSphere Portal and Maven

“Well it works on my machine” is the single most frustrating developer quote you will hear while working on a portal project. The open source world has experienced great success with automating builds and server deployments using apache maven and continuous integration (CI) servers like hudson, continuum, cruise control and others. Investing time in the beginning of your project to establish and use a build system provides several benefits:
  1. You get a precise deployment instructions by forcing deployment through scripts. Developers do not get to tweak things outside the process. You do not end up with one lead who does all the magic (and gets sick or goes on vacation like many of us other humans), or a series of differing answers from developers who each use their own methods.
  2. Deploying through scripts guarantees reliability and traceability for environments below production. The majority of your bugs should be found in these environments so diagnosing bugs becomes easier with tools like recent changes list and SCM commit comments exposed through the web interface of your CI server.
  3. The reports capability of maven allows leads and architects to catch integration and design issues sooner in the development cycle. (For example, CPD and PMD rules can look for import statements in layers of your architecture where they don’t belong, like importing java.sql.* in your UI layer when data access should be handled in the services layer).
  4. The continuous integration servers allow the quality assurance team to see where code is moving in real time so that they do not need to question developers about when versions are placed on different environments.
  5. Developers can check a single project out from SCM without needing a “magic workspace” of related dependencies because maven and the snapshot repository handles the dependencies.
The following series of posts will explain practical examples of maven and portal used at client sites.