Back to top
 
 
 

Customizing Models, DAOs, and Services

You can add custom tables into CloudPortal Business Manager and extend this to use it in CloudPortal Business Manager UI by following these steps:
  1. Create schema and insert default values using liquibase.
  2. Create model objects.
  3. Write DAOs to query the model objects (using hibernate).
  4. Write services to perform business operations.
  5. Use these services in web controllers to create a view.

Step 1. Create schema and insert default values using liquibase

To do any sql operation into CloudPortal Business Manager DB customization, you can write your liquibase change set into citrix.cpbm.custom.common/src/main/resources/citrix/cpbm/custom/db/portal/custom-db-config-v0.1.xml.

A sample liquibase change set looks as follows:
   <changeSet id="1366711278999-1" author="authorname">      <createTable tableName="user_login_audit">       <column name="id" autoIncrement="true" type="BIGINT">         <constraints nullable="false" primaryKey="true"/>       </column>       <column name="userid" type="BIGINT">         <constraints nullable="false"/>       </column>       <column name="remote_ip" type="VARCHAR(100)">        <constraints nullable="true"/>      </column>      <column name="created_at" type="DATETIME" remarks="The time at which user logged in.">        <constraints nullable="false"/>      </column>      <column name="version" type="INT" defaultValue="0"/>    </createTable>    <modifySql dbms="mysql">      <append value=" ENGINE=InnoDB DEFAULT CHARSET=utf8"/>    </modifySql>   </changeSet>    
Note: For more information on writing liquibase change set, please refer to http://www.liquibase.org/documentation/changes/index.html.

Step 2. Create model objects

To write the model object for this newly created table, add your java file under citrix.cpbm.custom.model/src/main/java/com/vmops/custom/model package. All new custom model should implement com.vmops.model.EntityBase.

An example model class looks as follows:
  /* Copyright (C) 2013 Citrix, Inc. All rights reserved. */     package com.citrix.cpbm.custom.model;   import java.util.Date;   import javax.persistence.Column;   import javax.persistence.Entity;   import javax.persistence.FetchType;   import javax.persistence.GeneratedValue;   import javax.persistence.GenerationType;   import javax.persistence.Id;   import javax.persistence.JoinColumn;   import javax.persistence.ManyToOne;   import javax.persistence.Table;   import javax.persistence.Temporal;   import javax.persistence.TemporalType;   import javax.persistence.Version;   import javax.validation.constraints.NotNull;   import javax.validation.constraints.Size;      import com.vmops.model.EntityBase;   import com.vmops.model.User;      /**    * UserLoginAudit model to capture user login details like    * <ul>    * <li>ip address from which the user has logged in.</li>    * <li>time at which user has logged in.</li>    * </ul>    *     * @author authorname    */   @Entity   @Table(name = "user_login_audit")   public class UserLoginAudit implements EntityBase {        /** The Constant serialVersionUID. */     private static final long serialVersionUID = 1L;        /**      * Primary key.      */     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id = 0L;        /** The user. */     @ManyToOne(fetch = FetchType.EAGER)     @JoinColumn(name = "userid", nullable = false, updatable = false)     @NotNull     private User user;        /** The remote ip. */     @Column(name = "remote_ip", length = 255)     @Size(max = 100)     private String remoteIp;        /** The created at. */     @Column(name = "created_at", nullable = false, updatable = false)     @Temporal(TemporalType.TIMESTAMP)     @NotNull     private Date createdAt = new Date();        /**      * Version number. used for Optimistic Concurrency Control.      */     @Column(name = "version")     @Version     private long version = 0;        /**      * Instantiates a new user login audit.      */     public UserLoginAudit() {       super();     }        /**      * Instantiates a new user login audit.      *       * @param user the user      * @param remoteIp the remote ip      */     public UserLoginAudit(User user, String remoteIp) {       super();       this.user = user;       this.remoteIp = remoteIp;     }        /**      * Gets the id.      *       * @return the id      * @see com.vmops.model.EntityBase#getId()      */     @Override     public Long getId() {       return null;     }      /**     * Sets the id.     *      * @param id the new id     */    public void setId(Long id) {      this.id = id;    }      /**     * Gets the user.     *      * @return the user     */    public User getUser() {      return this.user;    }      /**     * Sets the user.     *      * @param user the new user     */    public void setUser(User user) {      this.user = user;    }      /**     * Gets the remote ip.     *      * @return the remote ip     */    public String getRemoteIp() {      return this.remoteIp;    }      /**     * Sets the remote ip.     *      * @param remoteIp the new remote ip     */    public void setRemoteIp(String remoteIp) {      this.remoteIp = remoteIp;    }      /**     * Gets the created at.     *      * @return the created at     */    public Date getCreatedAt() {      return this.createdAt;    }      /**     * Sets the created at.     *      * @param createdAt the new created at     */    public void setCreatedAt(Date createdAt) {      this.createdAt = createdAt;    }      /**     * Gets the version.     *      * @return the version     */    public long getVersion() {      return this.version;    }      /**     * Sets the version.     *      * @param version the new version     */    public void setVersion(long version) {      this.version = version;    }      /**     * Hash code.     *      * @return the int     * @see java.lang.Object#hashCode()     */    @Override    public int hashCode() {      final int prime = 31;      int result = 1;      result = prime * result + ((this.createdAt == null) ? 0 : this.createdAt.hashCode());      result = prime * result + ((this.remoteIp == null) ? 0 : this.remoteIp.hashCode());      result = prime * result + ((this.user == null) ? 0 : this.user.hashCode());      return result;    }      /**     * Equals.     *      * @param obj the obj     * @return true, if successful     * @see java.lang.Object#equals(java.lang.Object)     */    @Override    public boolean equals(Object obj) {      if (this == obj) {        return true;      }      if (obj == null) {        return false;      }      if (getClass() != obj.getClass()) {        return false;      }      UserLoginAudit other = (UserLoginAudit) obj;      if (this.createdAt == null) {        if (other.createdAt != null) {          return false;        }      } else if (!this.createdAt.equals(other.createdAt)) {        return false;      }      if (this.remoteIp == null) {        if (other.remoteIp != null) {          return false;        }      } else if (!this.remoteIp.equals(other.remoteIp)) {        return false;      }      if (this.user == null) {        if (other.user != null) {          return false;        }      } else if (!this.user.equals(other.user)) {        return false;      }      return true;    }      /**     * To string.     *      * @return the string     * @see java.lang.Object#toString()     */    @Override    public String toString() {      StringBuilder builder = new StringBuilder();      builder.append("UserLoginAudit [");      if (this.id != null) {        builder.append("id=");        builder.append(this.id);        builder.append(", ");      }      if (this.user != null) {        builder.append("user=");        builder.append(this.user);        builder.append(", ");      }      if (this.remoteIp != null) {        builder.append("remoteIp=");        builder.append(this.remoteIp);        builder.append(", ");      }      if (this.createdAt != null) {        builder.append("createdAt=");        builder.append(this.createdAt);        builder.append(", ");      }      builder.append("version=");      builder.append(this.version);      builder.append("]");      return builder.toString();    }    }  

Step 3. Write DAOs to query the model objects (using hibernate)

To write custom DAO interface, create your DAO interface under citrix.cpbm.custom.common/src/main/java/com/citrix/cpbm/custom/persistence package. You have to extend the GenericDAO interface.

GenericDAO represents a DAO interface to interact with model objects persisted in the database. Typically, DAOs are created only for so-called root objects: model objects that are directly accessible. Dependent objects are traversed from these root objects.

An example of the DAO interface and its implementation is shown below:
   /* Copyright (C) 2013 Citrix, Inc. All rights reserved. */   package com.citrix.cpbm.custom.persistence;      import java.util.List;      import com.citrix.cpbm.custom.model.UserLoginAudit;   import com.vmops.model.User;   import com.vmops.persistence.GenericDAO;      /**   * The Interface UserLoginAuditDAO.   *    * @author authorname   */   public interface UserLoginAuditDAO extends GenericDAO<UserLoginAudit> {     /**     * Find login audit records.     *      * @param user the user     * @return the list     */    List<UserLoginAudit> findLoginAuditRecords(User user);    }    
   /* Copyright (C) 2013 Citrix, Inc. All rights reserved. */   package com.citrix.cpbm.custom.persistence.hibernate;      import java.util.List;   import java.util.Map;      import org.springframework.stereotype.Repository;      import com.citrix.cpbm.custom.persistence.UserLoginAuditDAO;   import com.citrix.cpbm.custom.model.UserLoginAudit;   import com.vmops.model.User;   import com.vmops.persistence.hibernate.GenericHibernateDAO;     /**   * The Class UserLoginAuditDAOImpl.   *    * @author authorname   */   @Repository("userLoginAuditDAO")   public class UserLoginAuditDAOImpl extends GenericHibernateDAO<UserLoginAudit> implements UserLoginAuditDAO {      /**     * Find login audit records.     *      * @param user the user     * @return the list     * @see com.citrix.cpbm.custom.persistence.UserLoginAuditDAO#findLoginAuditRecords(com.vmops.model.User)     */    @Override    public List<UserLoginAudit> findLoginAuditRecords(User user) {      Map<String, Object> conditions = getConditionsTemplate();      conditions.put("user", user);      return findByCriteria(null, conditions);    }    }    

Step 4. Write services to perform business operations

To create custom service layer API, you have to write your service interface under citrix.cpbm.custom.common/src/main/java/com/custom/service.

An example test service and its implementation is as shown below:
    /* Copyright (C) 2013 Citrix, Inc. All rights reserved. */   package com.citrix.cpbm.custom.service;      import java.util.Date;   import java.util.List;      import com.citrix.cpbm.custom.model.UserLoginAudit;   import com.vmops.model.User;     /**   * The Interface UserLoginAuditService.   *    * @author authorname   */  public interface UserLoginAuditService {      /**     * Find user login audit records.     *      * @param date the date     * @return the list     */    public List<UserLoginAudit> findUserLoginAuditRecords(Date date);      /**     * Find user login audit records.     *      * @param user the user     * @return the list     */    public List<UserLoginAudit> findUserLoginAuditRecords(User user);      public void saveAudit(UserLoginAudit userLoginAudit);    }    
   /* Copyright (C) 2013 Citrix, Inc. All rights reserved. */   package com.citrix.cpbm.custom.service.impl;      import java.util.Date;   import java.util.HashMap;   import java.util.List;   import java.util.Map;      import org.springframework.beans.factory.annotation.Autowired;  import org.springframework.stereotype.Service;    import com.citrix.cpbm.custom.persistence.UserLoginAuditDAO;  import com.citrix.cpbm.custom.service.UserLoginAuditService;  import com.citrix.cpbm.custom.model.UserLoginAudit;  import com.vmops.model.User;    /**   * The Class UserLoginAuditServiceImpl.   *    * @author authorname   */  @Service("userLoginAuditService")  public class UserLoginAuditServiceImpl implements UserLoginAuditService {      /** The user login audit dao. */    @Autowired    private UserLoginAuditDAO userLoginAuditDAO;      /**     * Find user login audit records.     *      * @param date the date     * @return the list     * @see com.citrix.cpbm.custom.service.UserLoginAuditService#findUserLoginAuditRecords(java.util.Date)     */    @Override    public List<UserLoginAudit> findUserLoginAuditRecords(Date date) {      Map<String, Object> conditions = new HashMap<String, Object>();      conditions.put("createdAt", date);      return userLoginAuditDAO.findByCriteria(null, conditions);    }      /**     * Find user login audit records.     *      * @param user the user     * @return the list     * @see com.citrix.cpbm.custom.service.UserLoginAuditService#findUserLoginAuditRecords(com.vmops.model.User)     */    @Override    public List<UserLoginAudit> findUserLoginAuditRecords(User user) {      return userLoginAuditDAO.findLoginAuditRecords(user);    }      /**     * Save audit.     *     * @param userLoginAudit the user login audit     * @see com.citrix.cpbm.custom.service.UserLoginAuditService#saveAudit(com.citrix.cpbm.custom.model.UserLoginAudit)     */    @Override    public void saveAudit(UserLoginAudit userLoginAudit) {      userLoginAuditDAO.save(userLoginAudit);      }  }    

Once you add a service, you have to export this service from citrix.cpbm.custom.common bundle, so that it can be used in citrix.cpbm.custom.portal bundle, where we have web controllers and views. To do this, you need to make and entry into citrix.cpbm.custom.common/src/main/resources/META-INF/spring/osgi-context.xml.

A sample entry looks as follows:
<osgi:service interface="com.citrix.cpbm.custom.service.UserLoginAuditService" ref="userLoginAuditService" />    

Step 5. Use these services in web controllers to create a view

To use the services exported from citrix.cpbm.custom.common bundle, you have to first import them into citrix.cpbm.custom.portal bundle. To do this you have to make an entry into citrix.cpbm.custom.portal/src/main/resources/WEB-INF/portal-osgi-context.xml.

A sample entry looks as follows:
<osgi:reference interface="com.citrix.cpbm.custom.service.UserLoginAuditService" id="userLoginAuditService" />  

To use the imported service in web controller and pass it to the view, access it by any other spring bean.

For example,
  @Autowired   @Autowired private UserLoginAuditService userLoginAuditService;   .   .   .    /**      * creates a login audit record for current logged in user.      * @param user      * @param request     */    private void createLoginAuditRecord(User user, HttpServletRequest request) {      UserLoginAudit userLoginAudit = new UserLoginAudit(user, getRemoteUserIp(request));      userLoginAuditService.saveAudit(userLoginAudit);    }    

Miscellaneous

  • The custom liquibase setting is available at citrix.cpbm.custom.common/src/main/resources/META-INF/spring/applicationContext-custom-liquibase.xml.
    The bean which runs the custom liquibase file looks as follows:
      <bean id="liquibaseportalcustomization" class="liquibase.integration.spring.SpringLiquibase">       <property name="dataSource" ref="dataSource" />       <property name="contexts" value="${liquibase.custom.context:basedata}"/>       <property name="changeLog" value="classpath:citrix/cpbm/custom/db/portal/cloud_portal-custom.xml" />       <property name="changeLogParameters">         <map>           <entry key="key-needed" value="to-avoid-npe-bug"></entry>           <entry key="portal_db" value="${profile.jdbc.database.schemaname}"/>           <entry key="field_encryption_key" value="${field.encryption.key}"/>        </map>      </property>      <property name="resourceLoader" ref="resourceLoader"  />    </bean>  

    The properties used in this bean are defined in cloud.properties located in your virgo-home>/repository/prop/cloud.properties.

  • Custom DAOs and Services bean are created in citrix.cpbm.custom.common/src/main/resources/META-INF/spring/applicationContext-custom-service.xml.
        <context:annotation-config />    <context:component-scan base-package="com.citrix.cpbm.custom.persistence" />    <context:component-scan base-package="com.citrix.cpbm.custom.service" />  

If you choose to change the custom service package name, you need to make the package entry in the exported package list in MANIFEST.MF file of citrix.cpbm.custom.common bundle as well imported package list in MANIFEST.MF file of citrix.cpbm.custom.portal bundle. Also, as specified above in Step 4 and Step 5, you need to make the necessary changes in osgi-context.xml of both these bundles.

 

Comments