CSC/ECE 517/M601 Design Document

From Expertiza_Wiki
Jump to navigation Jump to search

Add ability to update css through webapp

Example Video

A video example of this module can be seen here [1]

Team

Yuri Kolesnikov
Jonathan Wills
Jeffrey Plemmons
Roshna Agarwal

Our Work

Link to the OpenMRS ticket: https://tickets.openmrs.org/browse/TRUNK-3415
Link to our code in GitHub: https://github.com/ykolesn/openmrs-module-m601
Link to application: http://152.46.17.228:8081/openmrs-standalone

Purpose

The purpose of this module is to add the functionality of allowing the admin to customize the OpenMRS css file to their own specifications. By having the ability to customize the OpenMRS css file, the admin will be free to change the look and feel in their installation of OpenMRS.

Problem Definition

Add admin page for customization of the openmrs css file. Admins can 'override' any openmrs css with their own file by specifying that file in the openmrs runtime properties file. This would be best as a new module in openmrs or perhaps just adding a new feature in the Custom Logo module? The admin should see a page with a large text box. The text box value should be persisted in the database as a new object/table/column somehow. When the module starts up, the Activator is called. Modify the activator to update the filesystem css file with whatever is defined by the admin.

Design Requirements

1. The admin should be able to customize the openmrs css file through an admin page.
2. The admin should see a page with a large text box.
3. The text box content should be stored in the database.
4. The activator needs to be modified so that it updates the filesystem css file with whatever is defined by the admin.
5. Need to use Eclipse and Maven as development tools for the module.

Tasks

Week 1

  • Get OpenMRS Id
  • Get ticket assigned and in progress
  • Get openmrs module name assigned
  • Create openmrs module
  • Commit module to github
  • Check out module on partner machines
  • Get new admin page link
  • Create new spring controller and jsp page

Week 2

  • Create object for storing css in db
  • Create service layer and dao layer methods to save object
  • Connect controller to db object for saving + retrieving
  • Add unit tests for saving/retrieving

Week 3

  • Create settings page to allow admin to choose where tomcat is running
  • Add some magic so that module tries to guess where tomcat is running
  • Add ability to put the saved css into the right folder in tomcat so that the css is actually overriding the openmrs style.css file.

Development Tools

1. Eclipse<ref>http://en.wikipedia.org/wiki/Integrated_development_environment</ref>: Eclipse is the Integrated Development Environment used to develop, modify, and compile the code for our module.
2. Maven<ref>http://en.wikipedia.org/wiki/Apache_Maven</ref>: Maven is used through a plug-in in Eclipse to compile, run unit tests, and package all of the Java files in the module.
3. Tomcat<ref>http://en.wikipedia.org/wiki/Apache_Tomcat</ref>: Tomcat is the web-server used to run the application.
4. Hibernate<ref>http://en.wikipedia.org/wiki/Hibernate_(Java)</ref>: Hibernate is a built-in utility in the OpenMRS module, that is used to connect the Java classes to the database tables in the application. It configured the database table through an xml file: UpdateCSS.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="org.openmrs.module.updatecss">

<class name="UpdateCSS"
	table="css_properties">
        <id name="id" type="int" column="id">
            <generator class="native"/>
        </id>
		<property name="cssData" type="java.lang.String" column="css_location"
			length="255" not-null="true" />
		<property name="homeDirectory" type="java.lang.String" column="tomcat_home"
			length="255" not-null="true"/>
</class>
</hibernate-mapping>

Here in the UpdateCSS.hbm.xml we specify the table name and columns. Hibernate generates the table with the fields specified and handles all the necessary SQL calls and queries.
5. MySQL: MySQL<ref>http://en.wikipedia.org/wiki/Mysql</ref> is the RDBMS that is used to store the CSS data for the application.

Use Case

OpenMRS UI
This is the user interface for the UpdateCSS module. The initial start screen provides a default location for the css style sheet and default css code. Here the navigation bar is changed to "orange".

1. Log in to the Admin page with user "Admin" and password "Admin123"
2. Once logged in, click on "Administration" on the right-hand side of the navigation bar.
3. Under "Update CSS Module", click on "Manage module"
4. Here the user can enter their desired CSS preferences for customization.

Application Overview

Code Changes

Classes and Files Worked On

  • UpdateCSSActivator.java
  • UpdateCSS.java
  • UpdateCSSService.java
  • UpdateCSSServiceImpl.java
  • UpdateCSSDAO.java
  • HibernateUpdateCSSDAO.java
  • UpdateCSS.hbm.xml
  • liquibase.xml
  • moduleApplicationContext.xml
  • UpdateCSSServiceTest.java
  • manage.jsp
  • UpdateCSSManageController.java

Specific Changes

UpdateCSSActivator.java:
The activator class is an OpenMRS standard module class for initializing necessary components
when the module is in a certain state of activity. In our case, we needed to have the CSS
file overridden at module startup so the following function was added.

	/**
	 * @see ModuleActivator#started()
	 */
	public void started() {
		log.info("Update CSS Module started");
		
		// When the module loads, copy the css data
		// to the tomcat directory CSS file
		UpdateCSSService cssService = Context.getService(UpdateCSSService.class);
		cssService.copyCssDataToTomcatDirectory();			
	}

UpdateCSSServiceImpl.java:
Added below methods to UpdateCSSServiceImpl class:

  /**
+   * Replaces the text of the specified CSS file in the
+   * specified directory with the specified text
+   */ +  public void copyCssDataToTomcatDirectory(String directory, String cssText) {
+    File cssFile = new File(directory);
+    if (cssFile.exists()) {
+      writeDataToFile(cssFile, cssText);
+    }
+  }
+  
+  /**
+   * Copies the data stored in the DB into the CSS file that is saved in the 
+   * directory column of the css_properties table
+   */
+  public void copyCssDataToTomcatDirectory() {
+    UpdateCSS updateCSS = getData();
+    String cssDirectory = updateCSS.getHomeDirectory();
+    String cssText = updateCSS.getCssData();
+    copyCssDataToTomcatDirectory(cssDirectory, cssText);
+  }
+  
+  /**
+   * Writes the specified text to the specified CSS file
+   */
+  public void writeDataToFile(File cssFile, String cssText) {
+    try {
+      if (cssFile.exists()) {
+        PrintWriter writer = new PrintWriter(cssFile);
+        writer.print(cssText);
+        writer.close();
+      }
+    } catch (FileNotFoundException ex) {
+      
+    }
+  }
+  
+  /**
+   * Reads the data in the file at the specified path and returns
+   * a String with the contents. If the file doesn't exist
+   * then it returns an empty string
+   */
+  public String getCssTextFromFile(String filePath) {
+    String cssText = "";
+    try {
+      File cssFile = new File(filePath);
+      if (cssFile.exists()) {
+        cssText = FileUtils.readFileToString(cssFile);
+      }  
+    } catch (IOException ex) {
+    
+    }
+    return cssText;
+  }
+    

UpdateCSS.java:

Our model portion of the MVC pattern. This Java POJO represents the database record we are storing
to update/get CSS configuration setting.

/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://license.openmrs.org
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.module.updatecss;

import java.io.Serializable;
import org.openmrs.BaseOpenmrsObject;
import org.openmrs.BaseOpenmrsMetadata;

/**
 * It is a model class. It should extend either {@link BaseOpenmrsObject} or {@link BaseOpenmrsMetadata}.
 */
public class UpdateCSS extends BaseOpenmrsObject implements Serializable {

	private static final long serialVersionUID = 1L;
	
	private Integer id;
	private String homeDirectory;
	private String cssData;
	
	@Override
	public Integer getId() {
		return id;
	}
	
	@Override
	public void setId(Integer id) {
		this.id = id;
	}

	public String getHomeDirectory() {
		return homeDirectory;
	}

	public void setHomeDirectory(String homeDirectory) {
		this.homeDirectory = homeDirectory;
	}

	public String getCssData() {
		return cssData;
	}

	public void setCssData(String cssData) {
		this.cssData = cssData;
	}
}

UpdateCSSDAO.java/HibernateUpdateCSSDAO.java The DAO files carry the primary responsibility of interaction with the DB layer in the MVC architecture.
The data layer changes involved 3 separate components:

1. liquibase.xml file to configure our new table: css_properties
2. UpdateCSSDAO.java/HibernateUpdateCSSDAO.java - Interface/Implementation for DAO getter/setter.
3. UpdateCSS.hbm.xml - Hibernate configuration file for mapping DAO to new properties table.

liquibase.xml

Liquibase<ref>http://www.liquibase.org/documentation/</ref> is a method for automatically generating database changes at module startup. We used this to add
our new css_properties table.

    <changeSet id="updatecss-2013-04-22-26:00" author="yurijeffroshnajon" runOnChange="true">
     	<preConditions onFail="MARK_RAN">
             <not><tableExists tableName="css_properties"/></not>
        </preConditions>
        <comment>
             Create the css_properties table
        </comment>
        <createTable tableName="css_properties">
            <column name="id" type="int" autoIncrement="true">
                <constraints primaryKey="true" nullable="false"/>
            </column>
            <column name="css_location" type="longtext">
                <constraints nullable="false"/>
            </column>
            <column name="tomcat_home" type="varchar(255)">
                <constraints nullable="false"/>
            </column>
        </createTable>
    </changeSet> 

Hibernate

Hibernate<ref>http://www.hibernate.org/</ref> is a POJO-based implementation used for database interaction without the need for SQL queries.
Instead, by using some XML-based configuration files provided by the Hibernate framework, you can manipulate the
database using only Java objects. This is the mechanism we used for our database interaction. Our sample config file:

<hibernate-mapping package="org.openmrs.module.updatecss">

<class name="UpdateCSS"
	table="css_properties">
        <id name="id" type="int" column="id">
            <generator class="native"/>
        </id>
		<property name="cssData" type="java.lang.String" column="css_location"
			length="255" not-null="true" />
		<property name="homeDirectory" type="java.lang.String" column="tomcat_home"
			length="255" not-null="true"/>
</class>

</hibernate-mapping>

UpdateCSSService.java:
The interface for the UpdateCSSServiceImpl file described above.

UpdateCSSManageController.java:
Our controller utilized in the MVC pattern. We modified this file to initialize our main web page and populate it
with our existing configuration record.

	//this method creates an UpdateCSS object the first time this controller is loaded
	@ModelAttribute("updateCSS")
	public UpdateCSS getPatientSearchObject(){
		UpdateCSSService cssService = Context.getService(UpdateCSSService.class);
		UpdateCSS currCSS = cssService.getData();
		
		if (currCSS == null) {
			UpdateCSS newCSS = new UpdateCSS();
			newCSS.setHomeDirectory(System.getProperty("catalina.base") + "\\webapps\\openmrs-standalone\\style.css");
			newCSS.setCssData(cssService.getCssTextFromFile(newCSS.getHomeDirectory()));
			return newCSS;
		} else {
			return currCSS;
		}
	}

References

<references />