CleverGWT

From PlcWiki

(Difference between revisions)
Jump to: navigation, search
m (Unified look of the Clever System applications with AppEntryPoint)
 
(36 intermediate revisions not shown)
Line 1: Line 1:
== Installation Steps ==
== Installation Steps ==
-
* Repository: svn+ssh://username@oko.clever.cz  
+
* Repository: ssh://user@oko.clever.cz/home/git/CleverGWT/
* Path: /java/CleverGWT
* Path: /java/CleverGWT
* Entry-point descriptor ...gwt.xml:
* Entry-point descriptor ...gwt.xml:
Line 21: Line 21:
</java>
</java>
-
== Unified look of the Clever System applications with AppEntryPoint ==
+
== Unified look of the Clever System applications ==
 +
 
 +
=== Establishing a project ===
 +
 
 +
Choose: '''Google/Web Application Project'''. Package: '''cz.clever.nazevaplikace.gwt'''. GWT 2.4.0
 +
 
 +
=== Java Build Path ===
 +
 
 +
Projects - CleverGWT
 +
 
 +
Libraries - CleverGWT/lib/smartgwt-skins.jar, CleverGWT/lib/smartgwt.jar, CleverGWT/lib/log4j.jar
 +
 
 +
=== AppEntryPoint ===
AppEntryPoint is an implementation of the '''EntryPoint''' interface.
AppEntryPoint is an implementation of the '''EntryPoint''' interface.
-
Additionally steps: splash screen, sounds and icons. Images and icons are in CleverGWT/src/cz/clever/gwt/ext/public/images.
+
Invent an application name ''getAppName()'' a implementaci:
 +
 
 +
<java>
 +
public void drawContent(String initData, DataCallback<com.smartgwt.client.widgets.Canvas> callback) { callback.execute(new Canvas()); }
 +
</java>
 +
 
 +
<java>
 +
public void logout() {
 +
CallbackStatus status = null;
 +
ServiceCallback<Void> callback = new ServiceCallback<Void>(status, "Logout process") {
 +
@Override
 +
public void onSuccesss(Void result) {
 +
Window.Location.reload();
 +
}
 +
};
 +
Service.Util.get().logout(callback);
 +
}
 +
</java>
 +
 
 +
=== Interface Service a ServiceAsync ===
 +
 
 +
<java>
 +
@RemoteServiceRelativePath("service")
 +
public interface Service extends RemoteService, ServiceCore { }
 +
</java>
 +
 
 +
=== Server side - ServiceImpl ===
 +
 
 +
<java>
 +
public class ServiceImpl extends SecuredServiceServlet implements Service {
 +
 
 +
@Override
 +
protected String getAppName() {
 +
return "myAppName";// security role-name
 +
}
 +
 
 +
@Override
 +
protected KeyValueString getUserName() {
 +
return new KeyValueString() {
 +
 
 +
@Override
 +
public String getKey() {return "user-data-key";}
 +
 
 +
@Override
 +
public String getValue() {return (String)getUserData(); /* Default:String */}
 +
 
 +
@Override
 +
public void setValue(String value) {}
 +
 +
};
 +
}
 +
}
 +
</java>
 +
 
 +
=== web.xml ===
 +
 
 +
<xml>
 +
<servlet>
 +
    <servlet-name>serviceServlet</servlet-name>
 +
    <servlet-class>cz.clever.myapp.gwt.server.ServiceImpl</servlet-class>
 +
  </servlet>
 +
 
 +
  <servlet-mapping>
 +
    <servlet-name>serviceServlet</servlet-name>
 +
    <url-pattern>/myapp/service</url-pattern>
 +
  </servlet-mapping>
 +
</xml>
 +
 
 +
=== myapp.gwt.xml ===
 +
 
 +
Fill in correctly a Other module inherits:
 +
 
 +
<xml>
 +
<inherits name="com.google.gwt.i18n.I18N" />
 +
<inherits name="com.google.gwt.xml.XML" />
 +
<inherits name="com.google.gwt.http.HTTP" />
 +
<inherits name="com.smartgwt.SmartGwt" />
 +
<inherits name="cz.clever.gwt.ext.Module" />
 +
</xml>
 +
 
 +
=== log4j.properties ===
 +
 
 +
Copy to src.
 +
 
 +
=== Splash - landing page to the application ===
 +
 
 +
Known bug: if this page is not dynamic (jsp), then the server sends 304 (not modified) during authentication and this causes Firefox to not load the page.
 +
 
 +
It will be added to the input html page:
 +
 
 +
<xml>
 +
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
 +
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
 +
<META NAME="AUTHOR" CONTENT="CLEVER Soft s.r.o.">
 +
<META name="gwt:property" content="locale=en">
 +
</xml>
 +
 
 +
<xml>
 +
<body style="background-color: #445566">
 +
</xml>
 +
 
 +
<xml>
 +
<div style="border: 1px solid #7FBA00; position: absolute; left: 45%; top: 40%; padding: 2px; z-index: 20001; height: auto;">
 +
    <div style="background: white; font: bold 16px tahoma, arial, helvetica; padding: 10px; margin: 0; height: 34px; color: #444;">
 +
    <img src="myapp/images/loading32.gif" width="32" height="32" style="margin-right:8px; float:left; vertical-align:top;"/>
 +
    clever system<br/><span style="font: normal 10px tahoma, arial, helvetica;">My App Title</span>
 +
</div></div>
 +
</xml>
 +
 
 +
=== app.json ===
 +
 
 +
web.xml:
 +
 
 +
<xml>
 +
<context-param>
 +
<param-name>appname_</param-name>
 +
<param-value><![CDATA[App Name]]></param-value>
 +
</context-param>
 +
</xml>
 +
 
 +
<xml>
 +
<servlet>
 +
  <servlet-name>appInfo</servlet-name>
 +
  <servlet-class>cz.clever.gwt.ext.server.AppInfoServlet</servlet-class>
 +
  </servlet>
 +
 
 +
  <servlet-mapping>
 +
    <servlet-name>appInfo</servlet-name>
 +
    <url-pattern>/app.json</url-pattern>
 +
  </servlet-mapping>
 +
</xml>
 +
 
 +
=== Security - web.xml ===
 +
 
 +
<xml>
 +
<security-constraint>
 +
<web-resource-collection>
 +
<web-resource-name>WebResName</web-resource-name>
 +
<description></description>
 +
<url-pattern>/*</url-pattern>
 +
<http-method>GET</http-method>
 +
<http-method>POST</http-method>
 +
</web-resource-collection>
 +
<auth-constraint>
 +
<role-name>MyApp</role-name>
 +
</auth-constraint>
 +
</security-constraint>
 +
 +
<security-constraint>
 +
  <web-resource-collection>
 +
    <web-resource-name>Public</web-resource-name>
 +
    <url-pattern>/app.json</url-pattern>
 +
  </web-resource-collection>
 +
</security-constraint>
 +
 
 +
<login-config>
 +
<auth-method>FORM</auth-method>
 +
<form-login-config>
 +
<form-login-page>/Login.html</form-login-page>
 +
<form-error-page>/Login.html?failed</form-error-page>
 +
</form-login-config>
 +
</login-config>
 +
 
 +
<security-role>
 +
<role-name>MyApp</role-name>
 +
</security-role>
 +
</xml>
 +
 
 +
=== Sounds and pictures ===
 +
 
 +
Sounds and icons. Images and icons are in CleverGWT/src/cz/clever/gwt/ext/public/images.
 +
 
 +
The availability of resources is only after execution
 +
'''Google/GWT Compile'''.
 +
 
 +
Example of how to play audio (required audio tag in html):
 +
 
 +
<java>
 +
public static native void playAudio(String audioTagId, double volume) /*-{
 +
$doc.getElementById(audioTagId).volume = volume;
 +
$doc.getElementById(audioTagId).play();
 +
}-*/;
 +
</java>
 +
 
 +
Example of an html tag in the landing page (sounds are not physically part of the application where they are listed, but CleverGWT application):
 +
 
 +
<xml>
 +
<audio id="select" autobuffer="autobuffer" preload="auto">
 +
<source src="myapp/sound/select.ogg" type="audio/ogg">
 +
<source src="myapp/sound/select.mp3" type="audio/mpeg">
 +
</audio>
 +
</xml>
== ClvListGrid - Extension of ListGrid ==
== ClvListGrid - Extension of ListGrid ==

Current revision as of 14:38, 29 October 2020

Contents

Installation Steps

  • Repository: ssh://user@oko.clever.cz/home/git/CleverGWT/
  • Path: /java/CleverGWT
  • Entry-point descriptor ...gwt.xml:
 <inherits name="cz.clever.gwt.ext.Module" />
  • Don't forget to check your current version of the GWT

Resources

Resources are located in folder src/cz/clever/gwt/ext/public.

Example of icon usage:

 logoutBtn.setIcon(Resource.Util.getIconPath("door_out")); //$NON-NLS-1$

Unified look of the Clever System applications

Establishing a project

Choose: Google/Web Application Project. Package: cz.clever.nazevaplikace.gwt. GWT 2.4.0

Java Build Path

Projects - CleverGWT

Libraries - CleverGWT/lib/smartgwt-skins.jar, CleverGWT/lib/smartgwt.jar, CleverGWT/lib/log4j.jar

AppEntryPoint

AppEntryPoint is an implementation of the EntryPoint interface.

Invent an application name getAppName() a implementaci:

 public void drawContent(String initData, DataCallback<com.smartgwt.client.widgets.Canvas> callback) { callback.execute(new Canvas()); }
 public void logout() {
	CallbackStatus status = null;
	ServiceCallback<Void> callback = new ServiceCallback<Void>(status, "Logout process") {
		@Override
		public void onSuccesss(Void result) {
			Window.Location.reload();
		}
	};
	Service.Util.get().logout(callback);
 }

Interface Service a ServiceAsync

 @RemoteServiceRelativePath("service")
 public interface Service extends RemoteService, ServiceCore { }

Server side - ServiceImpl

 public class ServiceImpl extends SecuredServiceServlet implements Service {
 
	@Override
	protected String getAppName() {
		return "myAppName";// security role-name
	}
 
	@Override
	protected KeyValueString getUserName() {
		return new KeyValueString() {
 
			@Override
			public String getKey() {return "user-data-key";} 
 
			@Override
			public String getValue() {return (String)getUserData(); /* Default:String */} 
 
			@Override
			public void setValue(String value) {}
 
		};
	}
 }

web.xml

 <servlet>
    <servlet-name>serviceServlet</servlet-name>
    <servlet-class>cz.clever.myapp.gwt.server.ServiceImpl</servlet-class>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>serviceServlet</servlet-name>
    <url-pattern>/myapp/service</url-pattern>
  </servlet-mapping>

myapp.gwt.xml

Fill in correctly a Other module inherits:
 <inherits name="com.google.gwt.i18n.I18N" />
 <inherits name="com.google.gwt.xml.XML" />
 <inherits name="com.google.gwt.http.HTTP" />
 <inherits name="com.smartgwt.SmartGwt" />
 <inherits name="cz.clever.gwt.ext.Module" />

log4j.properties

Copy to src.

Splash - landing page to the application

Known bug: if this page is not dynamic (jsp), then the server sends 304 (not modified) during authentication and this causes Firefox to not load the page.

It will be added to the input html page:

 <meta http-equiv="content-type" content="text/html; charset=UTF-8">
 <META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
 <META NAME="AUTHOR" CONTENT="CLEVER Soft s.r.o.">
 <META name="gwt:property" content="locale=en">
 <body style="background-color: #445566">
 <div style="border: 1px solid #7FBA00; position: absolute; left: 45%; top: 40%; padding: 2px; z-index: 20001; height: auto;">
    <div style="background: white; font: bold 16px tahoma, arial, helvetica; padding: 10px; margin: 0; height: 34px; color: #444;">
    <img src="myapp/images/loading32.gif" width="32" height="32" style="margin-right:8px; float:left; vertical-align:top;"/>
    clever system<br/><span style="font: normal 10px tahoma, arial, helvetica;">My App Title</span>
 </div></div>

app.json

web.xml:

 <context-param>
	<param-name>appname_</param-name>
	<param-value><![CDATA[App Name]]></param-value>
 </context-param>
 <servlet>
  	<servlet-name>appInfo</servlet-name>
  	<servlet-class>cz.clever.gwt.ext.server.AppInfoServlet</servlet-class>
  </servlet>
 
  <servlet-mapping>
    <servlet-name>appInfo</servlet-name>
    <url-pattern>/app.json</url-pattern>
  </servlet-mapping>

Security - web.xml

 <security-constraint>
		<web-resource-collection>
			<web-resource-name>WebResName</web-resource-name>
			<description></description>
			<url-pattern>/*</url-pattern>
			<http-method>GET</http-method>
			<http-method>POST</http-method>
		</web-resource-collection>
		<auth-constraint>
			<role-name>MyApp</role-name>
		</auth-constraint>
	</security-constraint>
 
	<security-constraint>
  		<web-resource-collection>
    		<web-resource-name>Public</web-resource-name>
    		<url-pattern>/app.json</url-pattern>
  		</web-resource-collection>
	</security-constraint>
 
	<login-config>
		<auth-method>FORM</auth-method>
		<form-login-config>
			<form-login-page>/Login.html</form-login-page>
			<form-error-page>/Login.html?failed</form-error-page>
		</form-login-config>
	</login-config>
 
	<security-role>
		<role-name>MyApp</role-name>
	</security-role>

Sounds and pictures

Sounds and icons. Images and icons are in CleverGWT/src/cz/clever/gwt/ext/public/images.

The availability of resources is only after execution

Google/GWT Compile.

Example of how to play audio (required audio tag in html):

 public static native void playAudio(String audioTagId, double volume) /*-{
		$doc.getElementById(audioTagId).volume = volume;
		$doc.getElementById(audioTagId).play();
 }-*/;

Example of an html tag in the landing page (sounds are not physically part of the application where they are listed, but CleverGWT application):

 <audio id="select" autobuffer="autobuffer" preload="auto"> 
 <source src="myapp/sound/select.ogg" type="audio/ogg">
 <source src="myapp/sound/select.mp3" type="audio/mpeg">
 </audio>

ClvListGrid - Extension of ListGrid

Simplification of CRUD usage:

ListGrid grid = new ClvListGrid(new ClvListGrid.Delegate() {
 
			@Override
			public void executeUpdate(ClvListGridResponse response) {
				// Map<String, Object> reqMap = response.getRequestMap();
				// response.response(...
			}
 
			@Override
			public void executeRemove(ClvListGridResponse response) {}
 
			@Override
			public void executeFetch(ClvListGridResponse response) {}
 
			@Override
			public void executeAdd(ClvListGridResponse response) {}
 
			@Override
			public DataSourceField[] createFields() {
				return new DataSourceField[] { new DataSourceTextField("Field Name") };
			}
		});

Note: If you are implementing executeRemove/Add/Fetch you must call response.response(...). Not in executeUpdate.

Real-time data synchronization (only works with URL parameter "im"):

 grid = new ClvListGrid(delegate, "MySubscribeId");

SecuredServiceServlet

Benefits:

  • Request without GWT permutation header will be blocked (potential CSRF attack)
  • Authorization check before the servlet methods are called from client (methods must be annotated as Secured)
 public class MyGWTServiceImpl extends SecuredServiceServlet implements ...
 
 @Override
 protected boolean isInRole(String user, String method, Object value, Integer position) {
		// check for permission
 }

JettyLauncher

Allow you to set custom logging and configuration.

Example of startup arguments:

-startupUrl Entrypoint.html ... -server cz.clever.gwt.ext.server.JettyLauncher  ...

Inside a class:

 wac.setConfigurationClasses(new String[] { 
        "org.mortbay.jetty.webapp.WebInfConfiguration", 
        "org.mortbay.jetty.plus.webapp.EnvConfiguration",//jetty-env 
        "org.mortbay.jetty.plus.webapp.Configuration", //web.xml 
        "org.mortbay.jetty.webapp.JettyWebXmlConfiguration",//jettyWeb 
 });

DocumentServlet and UploadServlet

HttpServlet solution for uploading and downloading documents.

Example of upload servlet configuration:

 <servlet>
		<servlet-name>MaterialUpload</servlet-name>
		<servlet-class>cz.clever.cct.gwt.app.server.MyUploadServlet</servlet-class>
		<init-param>
	        <param-name>repository</param-name>
			<param-value>/tmp</param-value>
        </init-param>
        <init-param>
	        <param-name>maxMemSize</param-name>
			<param-value>2147483646</param-value>
        </init-param>
        <init-param>
	        <param-name>maxFileSize</param-name>
			<param-value>2147483646</param-value>
        </init-param>
	</servlet>

StringUtil

java.util.StringTokenizer is prohibited in the GWT client side. Here is my substitution:

 StringUtil.tokenizer("Jirka, Petr, Honza", ",", new ValueCallback() {
 
	@Override
	public void execute(String token) {
		// Your code
	}
 });

Way how to build a delimiter separated string from collection:

 ToString<MaterialOption> toStr = new ToString<MaterialOption>() {
 
	@Override
	public String get(MaterialOption obj) { //make a token from object
		return obj.toString();
		// or if you want: return obj == null? null:obj.getOptionString();
	}
 };
 // collection with filling of course
 Collection<MaterialOption> myCollection = new ArrayList<MaterialOption>();
 
 String result = StringUtil.toString(myCollection, ", ", toStr);

ParserCSV

 new ParserCSV(new ParserCSV.Delegate() {
 
			@Override
			public void token(String token, int position) {
				// working with parsed tokens
			}
 
			@Override
			public String getPath() { return "MyTable.csv"; }
 
			@Override
			public String getDelimeter() { return ";";}
 
			@Override
			public String getCharsetName() { return "UTF-16"; }
 });

BCrypt

String hashed = BCrypt.hashpw("password", BCrypt.gensalt());
boolean verified = BCrypt.checkpw("password", hashed);

String Externalizer (i18n)

Ant external task declaration example:

 <target name="externalizer">
		<taskdef name="externalizer" classname="cz.clever.gwt.ext.ant.Externalizer"/>
		<externalizer 
			        substitution="ClientConst.Util.get().%label()" 
			        labelMaxLength="20"
			        labelPrefix="lbl"
					fileConst="src/cz/clever/cct/gwt/app/client/ClientConst.java">
 
			        <fileset dir="src/cz/clever/cct/gwt/app/client">
			            <include name="*.java" />
			        	<exclude name="ClientConst.java"/>
			        </fileset>
			</externalizer>
	</target>

ClientConst.java (com.google.gwt.i18n.client.Constants) output example:

 @DefaultStringValue("Devices")
 String lblDEVICES();
Personal tools