Post-Conversion
To run the sample application please go to Gitpod, and look for the README.md with instructions on how to use it.
In case you want to review the source code of the migrated application, you can find it here: HelloWorld sample code. Also, the migrated code can be downloaded from PBMAPJavaHelloWorld.
This section explains in detail the following topics:
- 1.How does the migrated code look like?
- 2.Which changes were made over the existing code?
- 3.What are the helpers delivered by Mobilize for?
Before moving to explain the output code, first let's take a look at the PowerBuilder sample code:
forward
global type w_sample from window
end type
type dw_1 from datawindow within w_sample
end type
type sle_1 from singlelineedit within w_sample
end type
type st_1 from statictext within w_sample
end type
type cb_1 from commandbutton within w_sample
end type
end forward
global type w_sample from window
integer width = 1266
integer height = 844
boolean titlebar = true
string title = "Untitled"
boolean controlmenu = true
boolean minbox = true
boolean maxbox = true
boolean resizable = true
long backcolor = 67108864
string icon = "AppIcon!"
boolean center = true
dw_1 dw_1
sle_1 sle_1
st_1 st_1
cb_1 cb_1
end type
global w_sample w_sample
on w_sample.create
this.dw_1=create dw_1
this.sle_1=create sle_1
this.st_1=create st_1
this.cb_1=create cb_1
this.Control[]={this.dw_1,&
this.sle_1,&
this.st_1,&
this.cb_1}
end on
on w_sample.destroy
destroy(this.dw_1)
destroy(this.sle_1)
destroy(this.st_1)
destroy(this.cb_1)
end on
type dw_1 from datawindow within w_sample
integer x = 73
integer y = 256
integer width = 1070
integer height = 420
integer taborder = 20
string title = "none"
string dataobject = "d_sample_list"
boolean livescroll = true
borderstyle borderstyle = stylelowered!
end type
type sle_1 from singlelineedit within w_sample
integer x = 471
integer y = 80
integer width = 320
integer height = 112
integer taborder = 10
integer textsize = -10
integer weight = 400
fontcharset fontcharset = ansi!
fontpitch fontpitch = variable!
fontfamily fontfamily = swiss!
string facename = "Tahoma"
long textcolor = 33554432
borderstyle borderstyle = stylelowered!
end type
type st_1 from statictext within w_sample
integer x = 96
integer y = 80
integer width = 320
integer height = 112
integer textsize = -10
integer weight = 400
fontcharset fontcharset = ansi!
fontpitch fontpitch = variable!
fontfamily fontfamily = swiss!
string facename = "Tahoma"
long textcolor = 33554432
long backcolor = 67108864
string text = "Test Dw"
boolean focusrectangle = false
end type
type cb_1 from commandbutton within w_sample
integer x = 827
integer y = 80
integer width = 320
integer height = 112
integer taborder = 10
integer textsize = -10
integer weight = 400
fontcharset fontcharset = ansi!
fontpitch fontpitch = variable!
fontfamily fontfamily = swiss!
string facename = "Tahoma"
string text = "Add"
end type
event clicked;int li_row
if sle_1.text <> "" then
li_row = dw_1.insertrow( 0)
dw_1.setitem( li_row, 1, sle_1.text)
end if
end event
The converted code from the one above will consist of two parts:
- The Backend code containing the Java files and the helpers .war to emulate the PowerBuilder functionality.
- The Frontend code with the angular project for the web application.
As the image shown below:
The generated Frontend files are added in the automatically created folder sampleSite-angular, which contains an angular project template and all these converted files.
The structure of this sampleSite-angular folder is as follows:
- sampleSite-angular
- src
- app
- components
- sample
- w_sample
- w_sample.component.ts
- w_sample.component.css
- w_sample.component.html
- d_sample_list
- d_sample_list.component.ts
- d_sample_list.component.css
- d_sample_list.component.html
- index.ts
- app.component.css: stylesheet file used by the
app.component
- app.component.html: html file associated with the
app.component
- app.component.ts: startup angular component of the migrated application
- app.component.spec.ts: this is the file to include the frontend unit tests
- app.module.ts: this module includes all the sub-modules of all the application. e.g. You have two projects (pbt): project1.pbt and project2.pbt. This will yield two sub-modules: project1.module.ts and project2.module.ts
- app-routing.module.ts: this file handles the application routing
- root.component.ts: required file to define the root component of the application, where all other components will reside
- sample.module.ts: this module includes all the components of the sample pbt.
- index.html: this is the page that launches the angular startup component: app.component
- styles.css
- package.json: json file that contains the list of JavaScript packages required by the application.
Now let's take a look at these generated components. We will start with the HTML file:
Every control declared in the
w_sample
file will have its corresponding HTML tag; for example, the sample application has a Command Button
control, so the HTML has this:
The HTML tag
wm-command-button
is Mobilize's corresponding Command Button
angular component. Mobilize provides a series of angular components which you can use in the future when adding new controls to an existing screen.Following with these components review, we have the CSS file that matches with the previously reviewed HTML tag:
.sample_w_sample .w_sample {
width: 279px;
height: 211px;
background-color: ButtonFace;
}
.sample_w_sample .dw_1 {
position: absolute;
left: 5.77%;
top: 30.33%;
width: 84.52%;
height: 49.76%;
border-style: solid;
}
.sample_w_sample .sle_1 {
position: absolute;
left: 37.2%;
top: 9.48%;
width: 25.28%;
height: 13.27%;
font-weight: normal;
font-family: Tahoma;
color: WindowText;
border-style: solid;
}
.sample_w_sample .st_1 {
position: absolute;
left: 7.58%;
top: 9.48%;
width: 25.28%;
height: 13.27%;
font-weight: normal;
font-family: Tahoma;
color: WindowText;
background-color: ButtonFace;
}
.sample_w_sample .cb_1 {
position: absolute;
left: 65.32%;
top: 9.48%;
width: 25.28%;
height: 13.27%;
font-weight: normal;
font-family: Tahoma;
}
Every control declared in the
w_sample
file will have its corresponding CSS properties. For example, properties like facename, width, and height from the Command Button control are mapped into the CSS file like this:.sample_w_sample .cb_1 {
position: absolute;
left: 65.32%;
top: 9.48%;
width: 25.28%;
height: 13.27%;
font-weight: normal;
font-family: Tahoma;
}
Finally, the typescript file consists of an angular component class declaration like the one below, for the window class.
import { Component, ChangeDetectorRef, Renderer2, ElementRef, ViewEncapsulation} from "@angular/core";
import { BaseControlComponent, LengthConverter} from "@mobilize/powercomponents";
import { dataTransfer} from "@mobilize/base-components";
@Component({
selector : 'sample-w_sample',
templateUrl : './w_sample.component.html',
styleUrls : ['./w_sample.component.scss'],
encapsulation : ViewEncapsulation.None
})
@dataTransfer(['mobsample_sample_w_sample'])
export class w_sampleComponent extends BaseControlComponent {
constructor (changeDetector : ChangeDetectorRef,render2 : Renderer2,elem : ElementRef,lengthConverter : LengthConverter) {
super(changeDetector,render2,elem,lengthConverter);
}
}
Every window, for example
w_sample
, should have an Angular Component for the form to be displayed in the browser. This component defines three metadata properties:selector
— the component's CSS element selector. This selector tells Angular to create and insert an instance of the component where it finds the tag in a HTML template (e.g 'sample-w_sample')templateUrl
— the location of the component's template file. (e.g './w_sample.component.html')styleUrls
— the location of the component's private CSS styles. (e.g './w_sample.component.scss')
Let’s have a look at the converted code found in
w_sample.java
and Iw_sample.java
files.//Iw_sample.java
package com.sample.sample.sample;
import com.mobilize.jwebmap.models.WindowModel;
public interface Iw_sample extends WindowModel
{
w_sample.dw_1 getDw_1();
void setDw_1(w_sample.dw_1 value);
w_sample.sle_1 getSle_1();
void setSle_1(w_sample.sle_1 value);
w_sample.st_1 getSt_1();
void setSt_1(w_sample.st_1 value);
w_sample.cb_1 getCb_1();
void setCb_1(w_sample.cb_1 value);
void doConstructor();
void doWMInit();
}
//w_sample.java
package com.sample.sample.sample;
import org.springframework.beans.factory.annotation.Configurable;
import com.mobilize.jwebmap.aop.annotations.WebMAPStateManagement;
import com.sample.sample.sample.Iw_sample;
import com.sample.datamanagers.sample.sample.d_sample_list.d_sample_list;
import static com.mobilize.jwebmap.datatypes.ShortHelper.shortOf;
import static com.mobilize.jwebmap.conditionals.ConditionalsHelper.isTrue;
import static com.mobilize.jwebmap.conditionals.ComparisonHelper.notEq;
import static com.mobilize.jwebmap.datatypes.IntegerHelper.integerOf;
@Configurable
@WebMAPStateManagement
public class w_sample extends com.mobilize.jwebmap.models.WindowModelImpl implements Iw_sample
{
public dw_1 dw_1;
public dw_1 getDw_1() {
return this.dw_1;
}
public void setDw_1(dw_1 value) {
this.dw_1 = value;
}
public class dw_1 extends com.mobilize.jwebmap.datamanager.DataManagerControl
{
public dw_1(){}
public void doWMInit() {
super.doWMInit();
this.setX(shortOf(16));
this.setY(shortOf(64));
this.setWidth(shortOf(235));
this.setHeight(shortOf(105));
this.setTabOrder(shortOf(20));
this.setTitle(getLocalizedText("none"));
this.setDataManager(new d_sample_list());
}
}
public sle_1 sle_1;
public sle_1 getSle_1() {
return this.sle_1;
}
public void setSle_1(sle_1 value) {
this.sle_1 = value;
}
public class sle_1 extends com.mobilize.jwebmap.models.TextModel
{
public sle_1(){}
public void doWMInit() {
super.doWMInit();
this.setX(shortOf(104));
this.setY(shortOf(20));
this.setWidth(shortOf(70));
this.setHeight(shortOf(28));
this.setTabOrder(shortOf(10));
}
}
public st_1 st_1;
public st_1 getSt_1() {
return this.st_1;
}
public void setSt_1(st_1 value) {
this.st_1 = value;
}
public class st_1 extends com.mobilize.jwebmap.models.LabelModel
{
public st_1(){}
public void doWMInit() {
super.doWMInit();
this.setX(shortOf(21));
this.setY(shortOf(20));
this.setWidth(shortOf(70));
this.setHeight(shortOf(28));
this.setText(getLocalizedText("Test Dw"));
}
}
public cb_1 cb_1;
public cb_1 getCb_1() {
return this.cb_1;
}
public void setCb_1(cb_1 value) {
this.cb_1 = value;
}
public class cb_1 extends com.mobilize.jwebmap.models.ButtonModel
{
public cb_1(){}
public Integer clicked() {
Short li_row = 0;
if (isTrue(notEq(getSle_1().getText(), ""))){
li_row = shortOf(getDw_1().insertRow(0));
getDw_1().setItem(integerOf(li_row), shortOf(1), getSle_1().getText(), "String");
}
return 0;
}
public void doWMInit() {
super.doWMInit();
this.setX(shortOf(182));
this.setY(shortOf(20));
this.setWidth(shortOf(70));
this.setHeight(shortOf(28));
this.setTabOrder(shortOf(10));
this.setText(getLocalizedText("Add"));
this.addToEventList("bnclicked", true);
this.addToEventMapper("bnclicked", "clicked");
}
}
@Override
public void doConstructor() {
this.constructor();
this.dw_1.doConstructor();
this.sle_1.doConstructor();
this.st_1.doConstructor();
this.cb_1.doConstructor();
}
public w_sample(){
super ();
}
public void doWMInit() {
super.doWMInit();
this.dw_1 = new dw_1();
this.dw_1.setName("dw_1");
this.setSle_1(new sle_1());
this.sle_1.setName("sle_1");
this.setSt_1(new st_1());
this.st_1.setName("st_1");
this.setCb_1(new cb_1());
this.cb_1.setName("cb_1");
this.setTargetName("sample");
this.setLibName("sample");
this.setSimpleName("w_sample");
this.setName("mobsample_sample_w_sample");
this.setWidth(shortOf(279));
this.setHeight(shortOf(211));
this.setTitleBar(true);
this.setTitle(getLocalizedText("Untitled"));
this.setControlMenu(true);
this.setMinBox(true);
this.setMaxBox(true);
}
}
The most relevant changes made to the input code by WebMap framework are:
- Class declarations: WebMap adds
@Configurable
and@WebMAPStateManagement
annotations upon the class declaration.@Configurable@WebMAPStateManagementpublic class w_sample extends com.mobilize.jwebmap.models.WindowModelImpl implements Iw_sample{} - Variable declarations: WebMap adds a getter and setter for the variable declaration. For example, Get and Set methods for sle_1 PowerBuilder Single Line Edit component.public sle_1 sle_1;public sle_1 getSle_1() {return this.sle_1;}public void setSle_1(sle_1 value) {this.sle_1 = value;}
- doWMInit method declaration: WebMap adds
doWMInit
to thew_sample.java
. This method initializes the component and sets each component property values.public void doWMInit() {super.doWMInit();this.dw_1 = new dw_1();this.dw_1.setName("dw_1");this.setSle_1(new sle_1());this.sle_1.setName("sle_1");this.setSt_1(new st_1());this.st_1.setName("st_1");this.setCb_1(new cb_1());this.cb_1.setName("cb_1");this.setTargetName("sample");this.setLibName("sample");this.setSimpleName("w_sample");this.setName("mobsample_sample_w_sample");this.setWidth(shortOf(279));this.setHeight(shortOf(211));this.setTitleBar(true);this.setTitle(getLocalizedText("Untitled"));this.setControlMenu(true);this.setMinBox(true);this.setMaxBox(true);} - Type Mappings: WebMap converts the types of the source code to the corresponding type in the new Web Application. For example, datawindow
dw_1
has been mapped tocom.mobilize.jwebmap.datamanager.DataManagerControl
, andcb_1
Command Button
tocom.mobilize.jwebmap.models.ButtonModel
.public class dw_1 extends com.mobilize.jwebmap.datamanager.DataManagerControl{}public class cb_1 extends com.mobilize.jwebmap.models.ButtonModel{} - Internal component classes: WebMap adds an internal class for each component of the window, for example,
st_1
internal class added tow_sample.java
public class st_1 extends com.mobilize.jwebmap.models.LabelModel{}
All these attributes added by Mobilize let Mobilize's Weaving mechanism know it has to inject some code in compilation time to allow the proper execution of web applications.
The helpers delivered by Mobilize are a set of utilities whose function is to emulate PowerBuilder functionality into Java together with the FrontEnd WebMap part of the application. These helpers are divided into two projects:
Backend Helpers project contains:
- The core of your migrator
- Serialization mechanism
- Interceptors (AOP)
- View Models
- Events and Methods of Windows and Data Windows.
Those libraries represent the core of the PowerBuilder application in the
“Java platform”
. Also, some libraries providing the link and the control between the data and the Frontend user interface are also found here. Some of those libraries are:Datamanager
: a Java Plain Old Java Objects (POJO) implementing PowerBuilder Datawindow object. It provides services such as paged data retrieving and other data operations like insert, delete, update and read.Jasper Reports
: a dynamic component that represents a PowerBuilder Datawindow printing view, displayed as a PDF format.Database access
: this main component handles data persistence and encapsulates the client business logic in different database engines like Oracle and Sybase. This sub layer will provide services to get access to the persistent mechanism. It will be implemented using Spring JDBC, and it will include a Connection Pooling mechanism in order to improve the application's performance.State management
: due to its nature, a PowerBuilder application works under a state-full model. However, a Web application does not work like this. In order to preserve behavior a set of Java classes and some Spring Framework features such as Aspect Oriented Programming (AOP) will provide the Application layer with a state management mechanism.
These helpers are delivered as a war file, so the previous information intends to explain what is contain in them.