2014/03/12
12 Mar, 2014

[Tutorial] How to write a WSO2 Carbon Component

  • Amal Gunatilake
  • Senior Software Engineer - WSO2

First of all, in order to follow this tutorial successfully, you will need the following resources and basic knowledge in the areas listed below.

To understand the WSO2 Carbon Component Architecture you can follow the linked tutorial and then view this tutorial.

Once you have the basic knowledge on how the architecture works, you can start implementing a Carbon component feature.

In order to understand the concept, we take a look at a simple scenario.

Scenario

We will have a simple object database for storing Student details in the back-end component and let’s try to display those information at the front-end UI.

Student Manager UI

This will look like a useless feature. However, this is the best and simplest example to understand the concept of writing a Carbon component.

Creating the project structure

First, we will create the project structure to implement the carbon component (using Intellij IDEA editor in Ubuntu 13.04).

Create a maven project with the name student-manager. This will be the main project.

  • groupId - org.wso2.carbon
  • artifactId - student-manager
  • version - 4.2.0
  • packaging - pom
  • name - WSO2 Carbon - Student Manager

Note: If you are using an IDE to create the project, it will auto create the source folder. Since this project is a parent project, we can delete the src folder.

Now let’s create 3 sub maven projects inside the main project.

  • student-manager-components
    • artifactId - student-manager-components
    • packaging - pom
    • name - WSO2 Carbon - Student Manager Components
  • student-manager-features
    • artifactId - student-manager-features
    • packaging - pom
    • name - WSO2 Carbon - Student Manager Features
  • student-manager-repository
    • artifactId - student-manager-repository
    • packaging - pom
    • name - WSO2 Carbon - Student Manager Repository

Note: If you are using an IDE to create the projects, it will auto create the source folders. Since these projects are sub parent projects, we can delete the src folders. When adding these projects, the parent project should be updated accordingly with <modules> and the current project with <parent> tags. If you are using an IDE, it will auto generate them.

Now let’s create the server component inside the student-manager-components project. This will be an OSGI bundle. So, we have to configure the Apache Felix plugin to set up the configurations.

  • org.wso2.carbon.student.mgt
    • artifactId - org.wso2.carbon.student.mgt
    • packaging - bundle
    • name - WSO2 Carbon - Student Manager Server Component
    • plugin - maven-bundle-plugin

Note: When adding this project, the parent project should be updated accordingly with <modules> and the current project with <parent> tag. If you are using an IDE, it auto generates them.

The folder structure will look the image shown below.

student-manager-server-component

The current pom.xml files look as below

  • org.wso2.carbon.student.mgt → pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>student-manager-components</artifactId>
        <groupId>org.wso2.carbon</groupId>
        <version>4.2.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>org.wso2.carbon.student.mgt</artifactId>

    <packaging>bundle</packaging>
    <name>WSO2 Carbon - Student Manager Server Component</name>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
                        <Bundle-Name>${pom.artifactId}</Bundle-Name>
                        <Export-Package>org.wso2.carbon.student.mgt.*</Export-Package>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Note: When you export packages for the OSGI bundle, remember that if you are using any API classes or any other dependency in a separate package you have to export them as well. In this example, we will have our data classes in the org.wso2.carbon.student.mgt.data package. Exporting the parent mgt package will export everything needed.

  • student-manager-components → pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>student-manager</artifactId>
        <groupId>org.wso2.carbon</groupId>
        <version>4.2.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>student-manager-components</artifactId>

    <packaging>pom</packaging>
    <name>WSO2 Carbon - Student Manager Components</name>

    <modules>
        <module>org.wso2.carbon.student.mgt</module>
        <!-- There are 2 more projects to be added here later in this tutorial stub, ui -->
    </modules>
</project>
  • student-manager-features → pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
     	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
     	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
    	<artifactId>student-manager</artifactId>
    	<groupId>org.wso2.carbon</groupId>
    	<version>4.2.0</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>student-manager-features</artifactId>

	<packaging>pom</packaging>
	<name>WSO2 Carbon - Student Manager Features</name>
</project>
<!-- We will be again updating this pom later in this tutorial --><?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>student-manager</artifactId>
        <groupId>org.wso2.carbon</groupId>
        <version>4.2.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>student-manager-components</artifactId>

    <packaging>pom</packaging>
    <name>WSO2 Carbon - Student Manager Components</name>

    <modules>
        <module>org.wso2.carbon.student.mgt</module>
        <!-- There are 2 more projects to be added here later in this tutorial stub, ui -->
    </modules>
</project>
  • student-manager-repository → pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
     	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
     	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
    	<artifactId>student-manager</artifactId>
    	<groupId>org.wso2.carbon</groupId>
    	<version>4.2.0</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>student-manager-repository</artifactId>

	<packaging>pom</packaging>
	<name>WSO2 Carbon - Student Manager Repository</name>
</project>
<!-- We will be again updating this pom later in this tutorial -->
  • student-manager → pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
     	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
     	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>org.wso2.carbon</groupId>
	<artifactId>student-manager</artifactId>
	<version>4.2.0</version>
	<modules>
    	<module>student-manager-components</module>
    	<module>student-manager-features</module>
    	<module>student-manager-repository</module>
	</modules>

	<packaging>pom</packaging>
	<name>WSO2 Carbon - Student Manager</name>

    <repositories>
        <!-- Below configuration is used to download the relevant jars and plugins from the remote maven repositories -->
        <repository>
            <id>wso2-nexus</id>
            <name>WSO2 internal Repository</name>
            <url>https://maven.wso2.org/nexus/content/groups/wso2-public/</url>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </repository>

        <repository>
            <id>wso2.releases</id>
            <name>WSO2 internal Repository</name>
            <url>https://maven.wso2.org/nexus/content/repositories/releases/</url>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </repository>

        <repository>
            <id>wso2.snapshots</id>
            <name>WSO2 Snapshot Repository</name>
            <url>https://maven.wso2.org/nexus/content/repositories/snapshots/</url>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
            </snapshots>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>wso2.releases</id>
            <name>WSO2 internal Repository</name>
            <url>https://maven.wso2.org/nexus/content/repositories/releases/</url>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </pluginRepository>

        <pluginRepository>
            <id>wso2.snapshots</id>
            <name>WSO2 Snapshot Repository</name>
            <url>https://maven.wso2.org/nexus/content/repositories/snapshots/</url>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
            </snapshots>
            <releases>
                <enabled>false</enabled>
            </releases>
        </pluginRepository>
        <pluginRepository>
            <id>wso2-nexus</id>
            <name>WSO2 internal Repository</name>
            <url>https://maven.wso2.org/nexus/content/groups/wso2-public/</url>
            <releases>
                <enabled>true</enabled>
                <updatePolicy>daily</updatePolicy>
                <checksumPolicy>ignore</checksumPolicy>
            </releases>
        </pluginRepository>
    </pluginRepositories>
</project>

Writing the server component

Now let’s create the following folder structure in org.wso2.carbon.student.mgt project and add 2 java classes named as Student (in src/main/java/org/wso2/carbon/student/mgt/data/) and StudentManager (in src/main/java/org/wso2/carbon/student/mgt/). I will create the services.xml file as well in src/main/resources/META-INF/.

student-manager-server-component

The Student class will simply hold a few students' details (ID, first name, last name) with getters and setters.

package org.wso2.carbon.student.mgt.data;

public class Student {
	private int ID;
	private String firstName;
	private String lastName;

	public Student(int ID, String firstName, String lastName) {
    	this.ID = ID;
    	this.firstName = firstName;
    	this.lastName = lastName;
	}

	public int getID() {
    	return ID;
	}
	public void setID(int ID) {
    	this.ID = ID;
	}
	public String getFirstName() {
    	return firstName;
	}
	public void setFirstName(String firstName) {
    	this.firstName = firstName;
	}
	public String getLastName() {
    	return lastName;
	}
	public void setLastName(String lastName) {
    	this.lastName = lastName;
	}
}

The StudentManager class will create an array of students in the constructor and have a public method to return the array.

package org.wso2.carbon.student.mgt;

import org.wso2.carbon.student.mgt.data.Student;

public class StudentManager {
	private Student[] students;

	public StudentManager() {
    	students = new Student[2];
    	students[0] = new Student(1234,"Amal", "Gunatilake");
    	students[1] = new Student(4321, "John", "Carter");
	}

	public Student[] getStudents() {
    	return students;
	}
}

Finally the services.xml will expose the service named as StudentManager.

<serviceGroup>
	<service name="StudentManager" scope="transportsession">
    	<transports>
        	<transport>https</transport>
    	</transports>
    	<parameter name="ServiceClass">org.wso2.carbon.student.mgt.StudentManager</parameter>
	</service>

	<parameter name="adminService" locked="true">true</parameter>
	<parameter name="hiddenService" locked="true">true</parameter>
	<parameter name="AuthorizationAction" locked="true">/permission/protected/manage</parameter>
</serviceGroup>

Note: Here we have exposed StudentManager as our ServiceClass. This will make all the public methods in the StudentManager class as service operations (getStudents).

  • <transport>https</transport> - makes the service secure.
  • parameter name="adminService" - makes the service an admin service.
  • parameter name="hiddenService" - makes the service hidden to public.
  • parameter name="AuthorizationAction" - makes the service authorized.

Now we have completed the server component.

Writing the service stub

In order to create the stub, we need the wsdl exposed from the service we just created. But you won’t be able to access the wsdl from the browser since we have secured the connection. So, until we retrieve the wsdl, goto <CARBON_HOME>/repository/conf/carbon.xml and change the <HideAdminServiceWSDLs> parameter from true to false.

Now do a maven build and copy the org.wso2.carbon.student.mgt-4.2.0.jar inside the target folder and put it into the <CARBON_HOME>/repository/components/dropins/ folder in a Carbon server instance.

Start the Carbon server and go to https://localhost:9443/services/StudentManager?wsdl

Save the wsdl as StudentManager.wsdl for later use in the stub.

Put back the changed <HideAdminServiceWSDLs> parameter back to default setting.

Create a sub maven project named org.wso2.carbon.student.mgt.stub inside student-manager-components project.

  • artifactId - org.wso2.carbon.student.mgt.stub
  • packaging - bundle
  • name - WSO2 Carbon - Student Manager Stub
  • dependency - axis2
  • dependency - axiom
  • dependency - wsdl4j
  • plugin - maven-antrun-plugin
  • plugin - build-helper-maven-plugin
  • plugin - maven-bundle-plugin

Note: When adding this project, the parent project should be updated accordingly with <modules> and the current project with <parent> tag. If you are using an IDE, it will auto generate them.

Using wsdl2java along with maven-antrun-plugin we can generate the Java classes from the existing WSDL document.

Copy the StudentManager.wsdl to src/main/resources/ folder.

  • org.wso2.carbon.student.mgt.stub → pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
     	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
     	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
    	<artifactId>student-manager-components</artifactId>
    	<groupId>org.wso2.carbon</groupId>
    	<version>4.2.0</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>org.wso2.carbon.student.mgt.stub</artifactId>

	<packaging>bundle</packaging>
	<name>WSO2 Carbon - Student Manager Stub</name>

	<dependencies>
    	<dependency>
        	<groupId>org.apache.axis2.wso2</groupId>
        	<artifactId>axis2</artifactId>
        	<version>1.6.1.wso2v10</version>
    	</dependency>
        <dependency>
            <groupId>org.apache.axis2.wso2</groupId>
            <artifactId>axis2-client</artifactId>
            <version>1.6.1.wso2v10</version>
        </dependency>
    	<dependency>
        	<groupId>org.apache.ws.commons.axiom.wso2</groupId>
        	<artifactId>axiom</artifactId>
        	<version>1.2.11.wso2v4</version>
    	</dependency>
    	<dependency>
        	<groupId>wsdl4j.wso2</groupId>
        	<artifactId>wsdl4j</artifactId>
        	<version>1.6.2.wso2v4</version>
    	</dependency>
	</dependencies>

	<repositories>
		<repository>
		    <id>wso2-nexus</id>
		    <name>WSO2 internal Repository</name>
		    <url>https://maven.wso2.org/nexus/content/groups/wso2-public/</url>
		    <releases>
			<enabled>true</enabled>
			<updatePolicy>daily</updatePolicy>
			<checksumPolicy>ignore</checksumPolicy>
		    </releases>
		</repository>
	</repositories>

	<build>
    	<plugins>
        	<plugin>
            	<groupId>org.apache.maven.plugins</groupId>
            	<artifactId>maven-antrun-plugin</artifactId>
            	<version>1.1</version>
            	<executions>
                	<execution>
                    	<id>source-code-generation</id>
                    	<phase>process-resources</phase>
                    	<goals>
                        	<goal>run</goal>
                    	</goals>
                    	<configuration>
                        	<tasks>
                            	<path id="wsdl2java.classpath">
                                	<pathelement location="${settings.localRepository}/org/apache/ws/commons/axiom/wso2/axiom/1.2.11.wso2v4/axiom-1.2.11.wso2v4.jar"/>
                                	<pathelement location="${settings.localRepository}/org/apache/axis2/wso2/axis2-client/1.6.1.wso2v10/axis2-client-1.6.1.wso2v10.jar" />
                                	<pathelement location="${settings.localRepository}/org/apache/axis2/wso2/axis2/1.6.1.wso2v10/axis2-1.6.1.wso2v10.jar" />
                            	</path>
                            	<java classname="org.apache.axis2.wsdl.WSDL2Java" fork="true">
                                	<classpath refid="wsdl2java.classpath" />
                                	<arg line="-uri src/main/resources/StudentManager.wsdl -u -uw
   									 -o target/generated-code -p org.wso2.carbon.student.mgt.stub"/>
                            	</java>
                        	</tasks>
                    	</configuration>
                	</execution>
            	</executions>
        	</plugin>

        	<plugin>
            	<groupId>org.codehaus.mojo</groupId>
            	<artifactId>build-helper-maven-plugin</artifactId>
            	<executions>
                	<execution>
                    	<id>add-source</id>
                    	<phase>generate-sources</phase>
                    	<goals>
                        	<goal>add-source</goal>
                    	</goals>
                    	<configuration>
                        	<sources>
                            	<source>target/generated-code/src</source>
                        	</sources>
                    	</configuration>
                	</execution>
            	</executions>
        	</plugin>

        	<plugin>
            	<groupId>org.apache.felix</groupId>
            	<artifactId>maven-bundle-plugin</artifactId>
            	<extensions>true</extensions>
            	<configuration>
                	<instructions>
                    	<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                    	<Bundle-Name>${project.artifactId}</Bundle-Name>
                    	<Private-Package>
                    	</Private-Package>
                    	<Export-Package>
                        	org.wso2.carbon.student.mgt.*
                    	</Export-Package>
                    	<Import-Package>
                        	!org.wso2.carbon.student.mgt.*
                    	</Import-Package>
                    	<DynamicImport-Package>*</DynamicImport-Package>
                	</instructions>
            	</configuration>
        	</plugin>
    	</plugins>
        </plugins>
        <pluginManagement>
        	<plugins>
        		<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
        		<plugin>
        			<groupId>org.eclipse.m2e</groupId>
        			<artifactId>lifecycle-mapping</artifactId>
        			<version>1.0.0</version>
        			<configuration>
        				<lifecycleMappingMetadata>
        					<pluginExecutions>
        						<pluginExecution>
        							<pluginExecutionFilter>
        								<groupId>
        									org.codehaus.mojo
        								</groupId>
        								<artifactId>
        									build-helper-maven-plugin
        								</artifactId>
        								<versionRange>
        									[1.9.1,)
        								</versionRange>
        								<goals>
        									<goal>add-source</goal>
        								</goals>
        							</pluginExecutionFilter>
        							<action>
        								<ignore></ignore>
        							</action>
        						</pluginExecution>
        					</pluginExecutions>
        				</lifecycleMappingMetadata>
        			</configuration>
        		</plugin>
        	</plugins>
        </pluginManagement>
	</build>
</project>

Note:

  • Axis2 dependency has been used as the SOAP stack
  • The Apache Axiom library provides an XML Infoset compliant object model implementation, which supports on-demand building of the object tree
  • wsdl4j dependency has been used to generate the Java classes from the existing WSDL document using the wsdl2java
  • wsdl2java.classpath has been configured in the maven-antrun-plugin with the 3 dependencies as path elements.

<path id="wsdl2java.classpath">
<pathelement location="${settings.localRepository}/org/apache/ws/commons/axiom/wso2/axiom/1.2.11.wso2v4/axiom-1.2.11.wso2v4.jar"/>
<pathelement location="${settings.localRepository}/org/apache/axis2/wso2/axis2-client/1.6.1.wso2v10/axis2-client-1.6.1.wso2v10.jar" />
<pathelement location="${settings.localRepository}/org/apache/axis2/wso2/axis2/1.6.1.wso2v10/axis2-1.6.1.wso2v10.jar" />
</path>

Make sure those paths are set properly according to the local maven repository.

<java classname="org.apache.axis2.wsdl.WSDL2Java" fork="true">
<classpath refid="wsdl2java.classpath" />
<arg line="-uri src/main/resources/StudentManager.wsdl -u -uw
-o target/generated-code -p org.wso2.carbon.student.mgt.stub"/>
</java>

Here we have passed the StudentManager.wsdl to org.apache.axis2.wsdl.WSDL2Java class. This will generate the source code in target/generated-code inside org.wso2.carbon.student.mgt.stub package.

build-helper-maven-plugin will add the generated source code to the final JAR bundle.

Now we have completed creating the stub. If everything is configured properly the source will get generated and be included in the final JAR bundle after the maven build.

Writing the UI component

Let’s create the UI component with the stub dependency.

Create a sub maven project named org.wso2.carbon.student.mgt.ui inside student-manager-components project.

  • artifactId - org.wso2.carbon.student.mgt.ui
  • packaging - bundle
  • name - WSO2 Carbon - Student Manager UI Component
  • dependency - org.wso2.carbon.student.mgt.stub
  • plugin - maven-bundle-plugin

Note: When adding this project the parent project should be updated accordingly with <modules> and the current project with the <parent> tag. If you are using an IDE, it will auto generate them.

  • org.wso2.carbon.student.mgt.ui → pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>student-manager-components</artifactId>
        <groupId>org.wso2.carbon</groupId>
        <version>4.2.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>org.wso2.carbon.student.mgt.ui</artifactId>
    <packaging>bundle</packaging>
    <name>WSO2 Carbon - Student Manager UI Component</name>

    <dependencies>
        <dependency>
            <groupId>org.wso2.carbon</groupId>
            <artifactId>org.wso2.carbon.student.mgt.stub</artifactId>
            <version>4.2.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
                        <Bundle-Name>${project.artifactId}</Bundle-Name>
                        <Export-Package>
                            org.wso2.carbon.student.mgt.*
                        </Export-Package>
                        <Import-Package>
                            *;resolution:=optional
                        </Import-Package>
                        <Carbon-Component>UIBundle</Carbon-Component>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

In the UI component, we additionally mention it's the <Carbon-Component>UIBundle</Carbon-Component> when configuring OSGI.

Now let’s create the following folder structure in org.wso2.carbon.student.mgt.ui project and add the StudentManagerClient java class (in src/main/java/org/wso2/carbon/student/mgt/ui/).

package org.wso2.carbon.student.mgt.ui;

import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.wso2.carbon.student.mgt.data.xsd.Student;
import org.wso2.carbon.student.mgt.stub.StudentManagerStub;

import java.rmi.RemoteException;

public class StudentManagerClient {
    private StudentManagerStub stub;

    public StudentManagerClient(ConfigurationContext configCtx, String backendServerURL, String cookie) throws Exception{
        String serviceURL = backendServerURL + "StudentManager";
        stub = new StudentManagerStub(configCtx, serviceURL);
        ServiceClient client = stub._getServiceClient();
        Options options = client.getOptions();
        options.setManageSession(true);
        options.setProperty(org.apache.axis2.transport.http.HTTPConstants.COOKIE_STRING, cookie);
    }

    public Student[] getStudents() throws Exception{
        try{
            return stub.getStudents();
        }catch (RemoteException e) {
            String msg = "Cannot get the list of students"
                    + " . Backend service may be unavailable";
            throw new Exception(msg, e);
        }
    }
}

Note: Here in StudentManagerClient constructor StudentManagerStub has been implemented, which was generated from the stub project. 3 parameters have been taken in the constructor to pass into StudentManagerStub in order to create the HTTPS/SOAP transaction to the server component. The getStudents() method will retrieve the students array from the back-end server and return them to the UI.

  • Create index.jsp page in src/main/resources/web/student-mgt/.
<%@ page import="org.apache.axis2.context.ConfigurationContext" %>
<%@ page import="org.wso2.carbon.CarbonConstants" %>
<%@ page import="org.wso2.carbon.ui.CarbonUIUtil" %>
<%@ page import="org.wso2.carbon.utils.ServerConstants" %>
<%@ page import="org.wso2.carbon.ui.CarbonUIMessage" %>
<%@ page import="org.wso2.carbon.student.mgt.ui.StudentManagerClient" %>
<%@ page import="org.wso2.carbon.student.mgt.data.xsd.Student" %>
<%@ taglib prefix="fmt" uri="https://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib uri="https://wso2.org/projects/carbon/taglibs/carbontags.jar" prefix="carbon" %>
<%
        String serverURL = CarbonUIUtil.getServerURL(config.getServletContext(), session);
        ConfigurationContext configContext =
                (ConfigurationContext) config.getServletContext().getAttribute(CarbonConstants.CONFIGURATION_CONTEXT);
        String cookie = (String) session.getAttribute(ServerConstants.ADMIN_SERVICE_COOKIE);

        StudentManagerClient client;
        Student[] students;

        try {
            client = new StudentManagerClient(configContext, serverURL, cookie);
            students = client.getStudents();
        } catch (Exception e) {
            CarbonUIMessage.sendCarbonUIMessage(e.getMessage(), CarbonUIMessage.ERROR, request, e);
%>
            <script type="text/javascript">
                   location.href = "../admin/error.jsp";
            </script>
<%
            return;
    }
%>

<div id="middle">
    <h2>Student Management</h2>

    <div id="workArea">
        <table class="styledLeft" id="moduleTable">
                <thead>
                <tr>
                    <th width="20%">ID</th>
                    <th width="40%">First Name</th>
                    <th width="40%">Last Name</th>
                </tr>
                </thead>
                <tbody>
           <%
                   for(Student student:students){
           %>
                   <tr>
                       <td><%=student.getID()%></td>
                    <td><%=student.getFirstName()%></td>
                    <td><%=student.getLastName()%></td>
                </tr>
           <%
                   }
           %>
                </tbody>
         </table>
    </div>
</div>

Note: In order to create the StudentManagerClient, we have created the 3 parameters requested using the carbon core.

String serverURL = CarbonUIUtil.getServerURL(config.getServletContext(), session);
ConfigurationContext configContext = (ConfigurationContext) config.getServletContext().getAttribute(CarbonConstants.CONFIGURATION_CONTEXT);
String cookie = (String) session.getAttribute(ServerConstants.ADMIN_SERVICE_COOKIE);

When creating the content <div id="middle"> tag will set the ui content in the Carbon server page which will load the students information retrieved from the back-end.

  • Now we have to create the link in the Carbon server navigation panel to load the index.jsp page we just created. In order to do this we have to create a component.xml in src/main/resources/META-INF/ folder.
<component xmlns="https://products.wso2.org/carbon">
    <menus>
        <menu>
            <id>studentmgt_menu</id>
            <i18n-key>student.menu</i18n-key>
            <i18n-bundle>org.wso2.carbon.student.mgt.ui.i18n.Resources</i18n-bundle>
            <parent-menu>manage_menu</parent-menu>
            <link>../student-mgt/index.jsp</link>
            <region>region1</region>
            <order>50</order>
            <style-class>manage</style-class>
            <icon>../student-mgt/images/students.gif</icon>
            <require-permission>/permission/protected/manage</require-permission>
        </menu>
    </menus>
</component>

Note:

  • <id>studentmgt_menu</id> - Gives the id to the new link that points to the index.jsp
  • <i18n-key>student.menu</i18n-key> - This points to the link name which defines in the i18n bundle.
  • <i18n-bundle>org.wso2.carbon.student.mgt.ui.i18n.Resources</i18n-bundle> - This loads the i18n Resource.properties file (we will be adding this in the next few steps).
  • <parent-menu>manage_menu</parent-menu> - Defined the parent menu for the new link.
  • <link>../student-mgt/index.jsp</link> - The relative path to index.jsp
  • <region>region1</region> - Defines the region which the link should be locate.
  • <order>50</order> - Defines the link order.
  • <style-class>manage</style-class> - Load the css styles for the new link.
  • <icon>../student-mgt/images/students.gif</icon> - Defines a small icon to appear with the link.
  • <require-permission>/permission/protected/manage</require-permission> - Defines authorization category.

Create Resources.properties file in src/main/resources/org/wso2/carbon/student/mgt/ui/i18n/

student.menu=Students

Note: When creating the directory structure for Resource.properties file, if you are using an IDE, some of those IDEs create only one directory with the name org.wso2.carbon.student.mgt.ui.i18n. This is wrong. Make sure it has the write directory structure. Moreover, when configuring the path to component.xml omit the .properties ext.

Copy a small 24x24 pixels icon image into src/main/resources/web/student-mgt/images/.

icon

Now we have completed creating the UI Components as well. The Carbon Component is finalized.

  • org.wso2.carbon.student.mgt - server component OSGI bundle.
  • org.wso2.carbon.student.mgt.stub - communication stub OSGI bundle.
  • org.wso2.carbon.student.mgt.ui - UI component OSGI bundle.

The final folder structure for student-manager-components will look like the image shown below.

Final folder structure

Now, you have successfully created a Carbon Component!

To create a feature from the Carbon component, you can follow the tutorial on How to create a Feature from WSO2 Carbon component.

 

 

About Author

  • Amal Gunatilake
  • Senior Software Engineer
  • WSO2