jueves, 15 de abril de 2021

41. Common errors

1.persistence.xml: 

a. Verify that all the entities are defined inside a persistence unit 

<class>openadmin.model.gexflow.original.territori.CllCodigoPostal</class>
<class>openadmin.model.gexflow.original.territori.CllComarca</class>
<class>openadmin.model.gexflow.original.territori.CllHueco</class>

b. and also that no other classes are allowed

<exclude-unlisted-classes>true</exclude-unlisted-classes>

c. Verify that the same class (<class>myclass</class>) is not defined in 2 or more persistence units or in case it is duplicated, you must only use one persistence unit in your program


d. Verify which databases are only for query (and not updatable) and use the value "none" to schema modification


<property name="hibernate.hbm2ddl.auto" value="none" /> <!--NO SCHEMA MODIFICATION -->
<property name="hibernate.hbm2ddl.auto" value="update" /> <!--sCHEMA MODIFICATION !!!! -->

2. DB Server corruption

a. Symptoms: After a power failure, when a schema in a Postgres database is accessed from different web servers, one of the servers can fill the schema with "YAMLControlLoad" and cannot see the content of the schema, and the other one can see the content of the schema.

Maybe it is a caché problem or database corruption. If you have a backup, then drop the database and recreate it, and load the backup.

3. Tomcat fails

a. Symptons: Very slow tomcat startup and sometimes fails to deploy heavy applications

1.Save the WAR to deploy from the webapp folder
2. Delete the tomcat directory
3. Download a copy of the apache-tomcat.zip and reinstall it
4. Restore the WAR file into the webapp folder
5. Edit the conf/tomcat-users.xml as seen in Dantesque-Vaadin for allowing the user tomcat and roles tomcat and manager-gui
6. Edit wepapps/manager/META-IONF/context.xml for allowing access to other computers as seen in Dantesque-Vaadin
7. Execute bin/.startup.sh and try if has deloyed the application.

viernes, 5 de marzo de 2021

40. Creating the Server Socket

1. Get an Ubuntu server image

2. Set the IP static address as mentioned in Informatica Dantesca. 

3. Verify that the keyboard is set to your locale. (settings)

4. Change the host name: 

  sudo hostnamectl set-hostname my-new-name

5. Remove unwanted programs (maybe tomcat or others)

6. As we are going to use Selenium, we need to install:

     6.1. Google Chrome from: https://www.google.com/chrome/

     6.2. Chromium driver from: https://chromedriver.chromium.org/downloads and unzip the zip file in a folder (for instance "MyPrograms").

7 install ghoscript 

7. Create folders:

   /home/USER_INF/MyJars (IF,JaviSelenium,)

   /home/USER_INF/MyShells

8. Create folder myPrograms/SOCKET_SERVER

9. Copy in this folder these files or folders:

      9.1 startup_SocketServer.sh (shell script that is called form the service)

      9.2 socketserver.jar       

      9.3 Folder properties (and app.properties in this folder)

      9.4 Folder lib (with the dependencies: lombok, jsch, commons-lang, commons-io and common-exec

10. Create the service of the Socket server as mentioned in informatica Dantesca.

11. Install LibreOffice (minimal) for converting documents to PDF (apt-get install libreoffice --no-install-recommends)


miércoles, 3 de marzo de 2021

39. After generating the war. What to do?

1. Introduction

Most of the methods and procedures are executed in the standalone application called IFXX. There is another application for sending and receiving messages called SocketServer that are executed in the same server that IFXX. The Vaadin project must know the IP from the message server and the socket port to send and listen.

2. Modifying IFXX

The steps to do in this application are :

  1. Copy the dao.properties file  from the Vaadin project
  2. The persistence.xml MUST NOT include any reference to a JNI TOMCAT so the persistence unit must be:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
     <persistence-unit name="control_post" transaction-type="RESOURCE_LOCAL">
          <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
          <!-- BEGIN: FOR Data Source in Tomcat -->
          <!-- 
          <jta-data-source>java:comp/env/control_post</jta-data-source>
          -->
          <!--????? OJO: Revisar el context.xml de webapp/META-INF que apunta al servidor 192.168.28.29 -->
            
          <!-- END:   FOR Data Source in Tomcat-->
          
          <!-- The mapped supper class must be included in a <class> tag 2020.09.16 
               @see: https://stackoverflow.com/questions/4433341/what-is-the-right-path-to-refer-a-jar-file-in-jpa-persistence-xml-in-a-web-app
           -->
          
          <!--Mapped superclass  -->
          <class>openadmin.model.base.AuditIdLong          </class>
          
          <class>openadmin.model.control.Access            </class>
          <class>openadmin.model.control.Action            </class>
          <class>openadmin.model.control.ActionViewRole    </class>
          <class>openadmin.model.control.ClassName         </class>
          <class>openadmin.model.control.Configuracio      </class>
          
          <class>openadmin.model.control.EntityAdm         </class>
          <class>openadmin.model.control.MenuItem          </class>
          <class>openadmin.model.control.Program           </class>
          <class>openadmin.model.control.RoleGroup         </class>
          <class>openadmin.model.control.Role              </class>
          <class>openadmin.model.control.RolePerGroup      </class>
          <!--<class>openadmin.model.control.SiNo              </class> -->
          
          <class>openadmin.model.control.User              </class>
          
          <!-- YAML VIEW Classes  -->
          <!-- 
          <class>openadmin.model.yamlform.YAction        </class>
          <class>openadmin.model.yamlform.YComponent     </class>
          <class>openadmin.model.yamlform.YEvent         </class>
          <class>openadmin.model.yamlform.YProperty      </class>
          -->
          
          <!-- DBAYTO Metadata Classes  -->
          
          <class>openadmin.model.dbayto.metadatos.MtdRLTOptScpEnt          </class>
          <class>openadmin.model.dbayto.metadatos.EntsPerMetadataType      </class>
          <class>openadmin.model.dbayto.metadatos.MetadataType             </class>
          
           
          
          <exclude-unlisted-classes>true</exclude-unlisted-classes>
          
          <properties>
          		<property name="hibernate.dialect"	value="org.hibernate.dialect.PostgreSQLDialect" />
    		<property name="hibernate.hbm2ddl.auto" value="update" />
    		<property name="hibernate.show_sql" value="true" />				  
           		<!-- BEGIN: DataSource By Hibernate (NO TOMCAT) -->
           		<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> 
           		<!-- property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/openweb"/> -->
           		<property name="hibernate.connection.url" value="jdbc:postgresql://192.168.28.XX:5432/openweb" />   
    		<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
    		<property name="hibernate.connection.username" value="USER" />
    		<property name="hibernate.connection.password" value="PASSWORD" /> 
    		<!--  END:   DataSource By Hibernate (NO TOMCAT)  -->
          </properties>
    </persistence-unit>
    

  3. Take care that the persistence.xml in the Vaadin project and IF project is different!
  4. Generate the executable file and copy it to the folder informatica/MyJars/IF
  5. Copy configuration properties to this folder.

3. Modifying SocketServer

Must be executed in a server whose IP is in the app.properties of Vaadin. 
The properties file of SocketServer should be similar to this one:

1
2
3
4
5
#---location of shells scripts and java programs to be executed as external options
socket.port = 6666
java.path = /home/USER/MyPrograms/jdk-15.0.1/bin/java
jars.folder = /home/informatica/MyJars
shells.folder = /home/informatica/MyShells


4. Modifying Vaadin

In app.properties review this properties

socket.ip = 192.168.XX.XX (points the socket message server that execut3es the SocketServer)
socket.port = 6666 (Must be the same port of the SocketServer) 

martes, 9 de febrero de 2021

38. How to generate the WAR file? Solving some problems (org.codehaus.stax2.ri.SingletonIterator)

1. Procedure

 1. Change the file "dao.properties" and change the position of the comments, so that it points to the remote server:

#-------------------------------------------------------------------------------------------------------------------------------------
#PERSISTENCE UNITS AND HOSTS: 0:Control, 1:Postgres Gexflow1, 2:H2 Sicres ORVE, 3:Postgres Gexflow2, 4:SQL-SERVER Gestio-3 Casdastre, 5:SQL-SERVER Aytos, 6:pg Sicres ORVE
#-------------------------------------------------------------------------------------------------------------------------------------
#                 0            1                     3        4                      5                    6        7
persistence.units=control_post;PostgressGexflowJPAPU;sicresh2;sqlserver-gestio3-jtds;sqlserver-aytos-jtds;sicrespg;control_local
#persistence.units=control_local;PostgressGexflowJPAPU;sicresh2;sqlserver-gestio3-jtds;sqlserver-aytos-jtds;sicrespg;control_local

#                 0             1             2            3             4             5             6 
#                 pg-Control    pg-Gexflow    h2-ORVE      mssql-Cadatre mssql-Aytos   pg-ORVE       pg-control_local
persistence.hosts=192.168.28.XX;192.168.28.XX;192.168.10.XX;192.168.28.XX;192.168.28.XX;192.168.28.XX;192.168.10.XX
#persistence.hosts=192.168.10.XX;192.168.28.XX;192.168.10.XX;192.168.28.XX;192.168.28.XX;192.168.28.XX;192.168.10.XX

#                         0    1    2     3    4    5    6
persistence.units.active=true;true;false;true;true;true;false


2. Uncomment these 2 dependencies from the pom.xml

<dependency> 
 <groupId>org.codehaus.woodstox</groupId>
  <artifactId>stax2-api</artifactId>
  <version>4.2.1</version>
  <scope>runtime</scope>
</dependency>
		 
<dependency>
 <groupId>org.codehaus.woodstox</groupId>
  <artifactId>stax2-api</artifactId>
  <version>3.1.4</version>
  <scope>runtime</scope>
</dependency>

Take into account that these 2 dependencies are needed if:

  1. A class a FirtControlLoad is executed from eclipse as a Java application
  2. When deployed to the WebProp server
But it generates errors when not commented (due to Hibernate Envers) when executed from Eclipse as:  Run as ->Run on Server.

3. Verify that the file context.xml in "webapp/METAINF" folder points to the remote DB server IP

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/openweb" docBase="openweb"
        debug="5" reloadable="true" crossContext="true">
        
    <!-- url="jdbc:postgresql://localhost:5432/openweb"/> -->  
    <!-- OJO: Estamos en BDProp 192.168.28.29 -->
    <Resource 
      name="control_post"
      auth="Container"
      type="javax.sql.DataSource"
      username="USER"
      password="PASWORD"
      maxTotal="50"
      maxIdle="20"
      maxWait="10000"
      timeBetweenEvictionRunsMillis="180000"
      removeAbandonedOnMaintenance="true"
      removeAbandonedOnBorrow="true"
      driverClassName="org.postgresql.Driver"
      url="jdbc:postgresql://192.168.28.XX:5432/openweb" 
    />
      
    <!-- Added by Edu  @see https://stackoverflow.com/a/19003725/7704658 -->
    <!--  
    <Resource name="BeanManager" 
        auth="Container"
        type="javax.enterprise.inject.spi.BeanManager"
        factory="org.jboss.weld.resources.ManagerObjectFactory"/>  
    -->    
</Context>


4. Shutdown the tomcat server (tomcat_folder/bin/shutdown.sh) 

5. Generate the war : From Eclipse: Run as -> Maven build:

  • Goals: clean package
  • Profiles: production

6.Copy the file "xxx.war" from the target folder to the tomcat_folder/webapps and rename it to "WEBPROP.war"

7. Start up the tomcat server  (tomcat_folder/bin/startup.sh) 


8. Optional: If the application cannot run OK, then you should drop the "control" schema from the DBProp Postgress server and re-create it again.

2. Problem solving

1.  If the application cannot run OK, then you should drop the "control" schema from the DBProp Postgress server and re-create it again.

2. These error appears: 
Caused by: java.lang.NoSuchMethodError: 'org.codehaus.stax2.ri.SingletonIterator org.codehaus.stax2.ri.SingletonIterator.create(java.lang.Object)'
This error is caused because:
a. You have not uncommented the 2 dependencies from org.codehaus.woodstox in step2 and you are using the "WAR file" in the remote tomcat server, or 
b. You have not commented on these 2 dependencies in the pom.xml and you are executing the program from eclipse in the local machine  

miércoles, 20 de enero de 2021

37. My Wonderful Web Framework. (2) Actions. Defining the messagingsocket server

1. Introduction

There are 2 servers:

  1. Web server that makes the request to the socket server
  2. The Socket server that receives the request and executes a shell program
The shell program may include a shell script or it can execute a java program. The call to this programs is similar:


2. The SocketAction class in the webserver


This class inherits from BaseExecute that defines the base facilities.

It has a method "execute" that receives the fix and form params from the "application.yaml" file that is in the IFXX java project, for instance:

fixParams: '[STRING:JAVA_PATH -jar JARS_FOLDER/IF/MiJar.jar AYTOSOPERATION]', formParams: '{name: s_n, type: STRING, length: 1, value: S, required: true }'

In addition, it constructs a message to send to the socket server adding these additional parameters to the fix and form parameters:
  1. INET address of the user
  2. user name
  3. user-agent (Mozilla, Chrome..)
  4. Session-Id (HTTP)
Then the socket server IO and port is got from the properties: "var server".ip and "var server".port from the "app.properties" file.

The "var server" is an attribute of the action. By default, the value is "socket". This value is set in the application.yaml file when defining an action

server: socket,

The logic of sending and receiving messages with the server is defined in the procedure sendMessageCommand :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
	private void sendMessageCommand(String msg) throws IOException {
    	//System.out.println("Sending to server:"+ msg);
		String fileName1=null;
		byte[] bytes=null;
		String fileName1Key="(DOWNLOADER-FILENAME)";
		String bytesKey="(DOWNLOADER-BYTES)";
		String nRecords="(N.RECORDS=)";
    	out.println(msg);
    	
        String line = in.readLine().trim();
        
        //ERROR:* means that an error has occurred 
        //FIN:* means the end of the process
        while (! line.toUpperCase().startsWith("ERROR") &&
        	   ! line.toUpperCase().startsWith("FIN:")) { 
        	
        	if (line.contains(fileName1Key)) {
        		int pos=line.indexOf(fileName1Key);
        		fileName1=line.substring(pos+fileName1Key.length());
        	} else if (line.contains(bytesKey)) {
        		int pos=line.indexOf(bytesKey);
        		bytes=Base64.getDecoder().decode(line.substring(pos+bytesKey.length()));
        		bytes=ZipUtils.decompress(bytes);
        		addDownloaderEdu(fileName1, bytes);
        	} else if (line.contains(nRecords)) {
        		aS[2]=line.substring(line.indexOf(nRecords)+nRecords.length());
        		showMessage(line);
        	}
        	else showMessage(line, line.contains("ERROR"));
        	line = in.readLine();
        	//getAfectedRecords(line);
        }
        if (line.toUpperCase().startsWith("ERROR")) showError(line);
        else showMessage(line, line.contains("ERROR"));
    }

We can see that the condition for finishing the communication is that the message line starts with "ERROR" or "FIN:" . The first key indicates that an error has occurred, and the second one that the end of the process has been reached.

there are other keys that can contain the line message:
  1. (DOWNLOADER-FILENAME) and (DOWNLOADER-BYTES): To create a component called "DownloaderEdu" that downloads a file whose name is after the first key and the byte array to download is after the second key. NOTE that the byte arrays are compressed with ZIP and transformed to Base64. 
  2. (N.RECORDS=) the number of affected records by the process is sent after this key

3. The Socket server

There are 3 important files:
  • app.properties:  defines port to listen and paths to java and shells scripts
  • SimpleSocketServer class: the class with the main method to be executed once and manage the requests
  • ServerRequestHandler: Manages the treatment of the requests.
Here is the code:

app.properties:

1
2
3
4
5
#---location of shells scripts and java programs to be executed as external options
socket.port = 6666
java.path = /home/USER/MyPrograms/jdk-15.0.1/bin/java
jars.folder = /home/OTHERUSER/MyJars
shells.folder = /home/OTHERUSER/MyShells

SimpleSocketServer.java:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package u.requests.sockets;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Properties;

import utils.PropertiesUtils;

/**
 * Only open port for serving messages
 * The important part is the access to ServerRequestHandler03 that manages all the logic
 * @author ximo
 *
 */
public class SimpleSocketServer extends Thread
{
    private boolean isExecutedFromJar=false;  //????? Cambiar al compilar
	private ServerSocket serverSocket;
    private int port;
    private boolean running = false;
    //private String propsFileName="properties"+File.separator+"app.properties";
    private Properties props=null;

    public SimpleSocketServer(){
    	port=6666;
    	try {
			props=PropertiesUtils.getProperties(isExecutedFromJar,"app");
			port=Integer.parseInt(props.getProperty("socket.port",""+port));
		} catch (Exception e) {e.printStackTrace();}
    }
    
    public void startServer() {
        try {
            serverSocket = new ServerSocket( port );
            this.start();
        } catch (IOException e) { e.printStackTrace(); }
    }

    public void stopServer() {
        running = false;
        this.interrupt();
    }

    @Override
    public void run() {
        running = true;
        //This is for accepting multiple connections
        while( running ) {
            try {
                System.out.println( "System.out.println-->Listening for a connection" );

                // Call accept() to receive the next connection
                Socket socket = serverSocket.accept();

                // Pass the socket to the RequestHandler thread for processing
                ServerRequestHandler requestHandler = new ServerRequestHandler(socket, props );
                requestHandler.start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main( String[] args ) {
    	SimpleSocketServer server=null;
    	try {
    		server=new SimpleSocketServer();
    		System.out.println( "SimpleSocketServer03.Start server on port: " + server.port );
			server.startServer();
			/*
        	// Automatically shutdown in 1 minute
        	try {
            	Thread.sleep( 60000 );
        	} catch( Exception e ) { e.printStackTrace(); }
			 */
		} catch (Exception e) {	
			if (server!=null) {
				server.stopServer();
				System.out.println("server stopped");
				e.printStackTrace();
			}	
		}	
    }
}


ServerRequestHandler.class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package u.requests.sockets;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Properties;

import utils.CmdUtils;

class ServerRequestHandler extends Thread {

    private Socket socket;
    private String command="";
    //private String myPath="";
    private String shellsFolder="";
    private String jarsFolder="";
    private String javaPath="";
    private Properties props=null;
    private Boolean isError=false;
    private BufferedReader inSocket =null;
    private PrintWriter outSocket=null;
    private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    
    public ServerRequestHandler(Socket socket, Properties props ) { 
    	this.socket = socket; 
    	this.props=props;
    }
    
    @Override
    public void run() {
    	
        try {
            System.out.println( "RH-->Received a connection" );

            // Get input and output streams
            inSocket = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
            outSocket = new PrintWriter( socket.getOutputStream(), true );
            
            
            command = inSocket.readLine();
            outSocket.println("4.1 Des del server: Obtenint comandament a executar...("+ command +")");
            
            if (command.trim().length() <2) showError("ERROR: Comandament curt:("+ command + ")");
            else {
            	try {
            	
				shellsFolder=props.getProperty("shells.folder").trim();
				jarsFolder=props.getProperty("jars.folder").trim();
				javaPath=props.getProperty("java.path").trim();
				//command=myPath.trim() + File.separator+ command;
				command=command
						.replace("JAVA_PATH", javaPath)
						.replace("SHELLS_FOLDER", shellsFolder)
						.replace("JARS_FOLDER", jarsFolder);
				System.out.println("COMMAND="+ command);
				} catch (Exception e) { showError("ERROR : Obrint paràmetres del fitxer de propietats... app.properties" + e.getMessage());}
		    }
            if (!isError) {
            	outSocket.println("4.2 Des del server: Executant...("+ command +")");
            	try {
    				//Execute and wait for end of execution
    				if(CmdUtils.execProgram(command, null, null, false, outputStream) !=0) showError("ERROR 4: Executant " + command + "... ");
    			}catch (Exception e) { showError("ERROR 4.2: Executant " + command + "... " + e.getMessage());}
    		}
            
            if (!isError) {
            	outSocket.println("4.3 Des del server: Informant ...");
            	try {
    				//Show execution details
            		int i=0;
            		for (String line : outputStream.toString().split("\\n")) {
            			String lineUP=line.toUpperCase();
            			if (lineUP.contains("SHOWMESS") || lineUP.contains("ERROR")) {
            				outSocket.println("4.3." + ++i + "-->" + line);
            				System.out.println("4.3." + i + "-->" + line);
            			}	
            		}	
    			}catch (Exception e) { showError("ERROR 4.3: Executant " + command + "... " + e.getMessage());}
    		}
            
            if (!isError) outSocket.println("FIN:");  //END OF PROCESS SIGNAL!!
                      
            // Close our connection
            inSocket.close();
            outSocket.close();
            socket.close();

            System.out.println( "Rh:->Connection closed" );
        } catch( Exception e ) { e.printStackTrace(); }
    }
        
    private void showError(String message) {
    	isError=true;
        outSocket.println(message);
    }
}



36. My Wonderful Web Framework. (1) Actions. YAML definition

 1.  Actions

Falta definir els métodes de la classe actual. Cal fer un wrapper per a que una classe  que assumisca una cride d'una altra i que herede de BaseExecute!!!!!


An action consists of executing a method from a class. The actions can be defined in menus and forms:

  1. Actions that are executed in a "MenuItem" of type "action" ("command" and "1" are synonymous). Only one action per "MenuItem" is allowed
  2. Actions that are executed inside a form (represented by a class) in a "MenuItem" of type "form" (take into account that there are several types of forms: default(2), custom(3) and yaml (4)
An action is defined by:
  1. The class that contains the method to execute
  2. The method to execute
  3. The parameters that accept the class. That can be fixed and/or asked by means of a form
  4. The type of action: the possible values are: inner: In this case the class to execute is in the same Vaadin module, shell: In this case a call to a shell script in the property "execution.folder" of the property file "app.properties", socket: This is very important as delegates the execution to another server by means of sending messages through sockets, avoiding java RMI
  5.  Optional information: role group that is allowed to execute the program, icon to show, ask for confirmation, char to show in combo in grid form, if need a record id to operate,

2. Defining the actions

Here is a snippet of YAML code defining both types of actions $$$


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
menuItems: 
  [
    #1. MenuItem with an action of type socket (executed in another server (action: socket type))
    { description: firstcontrolloadyaml_control, className: openadmin.actions.SocketActions, icon: fa-upload,   
     type: action, defaultActions: false,
     actions: 
       [ 
         { name: dataLoad,  type: socket, method: execute,    
           fixParams: '[STRING:JAVA_PATH -jar JARS_FOLDER/IF/MiJar.jar FIRSTCONTROLLOAD]', 
           roleGroup: gadmin, icon: fa-upload, executedInGrid: false, needId: false  
         } 
       ]
    },  

    #2. MenuItem with an action of type inner (executed in a class included in the "war" file (action: inner type))
    { className: openadmin.actions.u.request.MetadataLoader, icon: fa-upload,   
      type: action, defaultActions: false, 
      actions: 
        [ 
          { name: dataLoad,  method: dataLoad,  fixParams: '[DAO-METADATA]',   
            roleGroup: gadmin,   icon: fa-upload, executedInGrid: false, needId: false  
          } 
        ]
    },
   
    #3. A form of type custom that shows the "users" and has som actions 
    { className: openadmin.model.control.User, description: User_Custom, icon: fa-user, combo: false, type: custom,
      actions: 
        [ 
          #3.1 Action in the form that calls a java program in another server (action: socket type)
          { name: getFactures, confirm: false, idChar: E, type: socket, method: execute, 
            fixParams: '[STRING:JAVA_PATH -jar JARS_FOLDER/IF/MiJar.jar AYTOSOPERATION]', 
            formParams: '{name: s_n, type: STRING, length: 1, value: S, required: true }', 
            roleGroup: gnew,   icon: fa-file-invoice-dollar, executedInGrid: false, needId: false  
          } ,
          
          #3.2 Example where the class of the action is a shell script executed in the same server (action: shell type)
          { name: dni,  confirm: false, idChar: 7, method: verifyDNI, roleGroup: gadmin,  type: shell, icon: fa-id-card, 
            fixParams: '[STRING:bshComprobaciones.sh];[ID];[STRING:verifyDNI]'    
          } ,

          #3.3 Example where the class of the action is the same class (action: inner type)
          { name: kkerr, confirm: false,   idChar: 8, type: inner,  method: kk1,            
            fixParams: '[ID]', roleGroup: gadmin,   icon: fa-cloud-showers-heavy    
          },  
          
          #3.4 Action in the form that calls a shell script in another server (action: socket type)
          { name: prova, confirm: true,    idChar: C, type: socket, executedInGrid: false,  
           fixParams: '[STRING:SHELL_PATH/shProva01.sh]', roleGroup: gadmin,   icon: fa-beer    
          } 
        
        ]
    }
  ] 


Line 4 defines a "menuitem" that is of type action, so it has only one action of type socket

Line 14 defines a "menuitem" that is of type action, so it has only one action of type inner


Line 26 defines a form with 4 actions of different types Socket (external java program execution), shell (in the same server), inner with a method of the "entity class" and another Socket (external shell script in another server)

Here are some important parameters:
  • className: The class that owns the method to execute, by default is the class shown in the form
  • method: the name of method of the class to execute. By default is the "execute"
  • name: The name that will be shown to the user and will be converted to i18n (internationalization)
  • roleGroup: the authorized group top execute the method
  • idChar: The char to show in the group of actions (in the combo) to be executed in a form. It must be set when the actions are executed from a form. Each action should have a unique "idChar"
  • icon: The name of the "font-awesome icon" to show.
  • needId: If the action is executed on one record (that is identified by its Id). The Id is supplied by the current record.
  • executedInGrid: If this action can be executed in a record of the grid and showed in the combo of options
  • confirm: If ask for confirmation of the user before executing the action. 

3. The fixParams parameter

This parameter is important as it has a peculiar format. It is a list of constant parameters. Every parameter must be between "square brackets" "[ ]" and separated by a colon ";"

Here is an example:


fixParams: '[DAO-H2];[ID];[INT:2];[LONG:9];[STRING:cat];[SERVER:0]', 

Where:
  • DAO-H2 is the DAO Object form the H2 database, there ara also other DAOs to other persistence units.
  • ID is the id of the Base Object
  • INT:2 is the integer value "2"
  • LONG:9 is the long value "9"
  • STRING:cat is the String value "cat"
  • SERVER:0 returns the server + ":" + port for specifiying a socket to a server to pass messages.
Al all these parameters are stored in a List

4. The formParams parameter

This parameter is important as it has a peculiar format. It is a list of parameters that will be required within a form to the user.

Each parameter is defined between brackets "{ }" and forms a YAML structure.


formParams: '{name: year, type: INT, length: 4, value: $YEAR, required: true }, {name: registro, type: INT, length: 6, value: 0, required: true }',

The labels of the parameters are:
  • name: name of the parameter
  • type: INT, LONG, STRING ...
  • length: max number of chars of the parameter 
  • required; true of false
  • value: default value. It can be:
    • $YEAR : Actual year
    • $YEAR_PREVIUOS_MONTH: Year of the previous month
    • $MONTH: Actual month (1 to 12) 
    • $PREVIOUS_MONTH: The previous month (1 to 12)
    • A constant

lunes, 12 de octubre de 2020

35. Migrating to Vaadin version 17 & 18. Problems in annotaitons: @Push and @Theme

see: Vaadin Forum

1.VaadinServlet/CdiVaadinServlet implementions

In version 14

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package openadmin.listeners;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import com.vaadin.cdi.CdiVaadinServlet;
import com.vaadin.flow.server.Constants;
//import com.vaadin.flow.server.VaadinServlet;


/**
 * Information about app servlet 
 * 
 * Necessary for defining i18n Provider
 * @author ximo 
 *
 */
@SuppressWarnings("serial")
@WebServlet(
	urlPatterns = "/*", 
	name = "slot", 
	asyncSupported = true, //For @Push
	
	
	initParams = {
		// I18N Provider for translation of labels	
        //Vaadin 14,15,16
	@WebInitParam(name = Constants.I18N_PROVIDER, value = "openadmin.i18n.MyI18nProvider"),	
	// Enable pmpm instead of npm	2020-05-27 for Vaadin 15 
	// @see https://dantesquevaadin.blogspot.com/2020/05/32-vaadin-15-new-version-using-pnpm.html
	@WebInitParam(name = "pnpm.enable", value = "true")
	})

// Deprecated. @see https://vaadin.com/docs/v14/flow/production/tutorial-production-mode-basic.html
//@VaadinServletConfiguration(productionMode = false)

//public class ApplicationServlet extends VaadinServlet {
public class ApplicationServlet extends CdiVaadinServlet {
}


now in version 17, there are several changes


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package openadmin.listeners;

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;

import com.vaadin.cdi.CdiVaadinServlet;
//import com.vaadin.flow.server.VaadinServlet;
import com.vaadin.flow.server.InitParameters;

/**
 * Information about app servlet 
 * 
 * Necessary for defining i18n Provider
 * @author ximo 
 *
 */
@SuppressWarnings("serial")
@WebServlet(
	urlPatterns = "/*", 
	name = "slot", 
	asyncSupported = true, //For @Push
	
	//pushmode = "manual",
	
	initParams = {
		//Vaadin 17
		// I18N Provider for translation of labels	
     		@WebInitParam(name = InitParameters.I18N_PROVIDER, value = "openadmin.i18n.MyI18nProvider"),
        	@WebInitParam(name = InitParameters.SERVLET_PARAMETER_PUSH_MODE, value= "PushMode.MANUAL" ),
        	@WebInitParam(name = InitParameters.SERVLET_PARAMETER_ENABLE_PNPM, value= "true" ),
        	//End Vaadin17
	})

//public class ApplicationServlet extends VaadinServlet {
public class ApplicationServlet extends CdiVaadinServlet {
}


2.VaadinServiceInitListener implementions and @Push

In version 14, the @Push annotation was placed  in the main form, now in version 17 gives a runtime error: 

Found app shell configuration annotations in non `AppShellConfigurator` classes.

Please create a custom class implementing `AppShellConfigurator` and move the following annotations to it:

    - @Push from openadmin.ui.forms.MainView

So, the class implementing VaadinServiceInitListener should now implement also the AppShellConfigurator interface and will contain the @Push annotation

Now let's see the new class with the old version aspects commented


In version 18 also complains about the @Theme annotation and does not want it in the main form



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package openadmin.listeners;


import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.component.page.Push;
import com.vaadin.flow.server.ServiceInitEvent;
import com.vaadin.flow.server.VaadinServiceInitListener;
import com.vaadin.flow.shared.communication.PushMode;

import openadmin.ui.forms.LoginForm;
import openadmin.vaadin.http.SessionParams;
import openadmin.vaadin.http.VaadinHttpUtils;



/**
 * This class is used to listen to BeforeEnter event of all UIs in order to
 * check whether a user is signed in or not before allowing entering any page.
 * It is registered in a file named
 * com.vaadin.flow.server.VaadinServiceInitListener in META-INF/services.
 * 
 * NOTE that a SessionScopped object cannot be injected so, to know if the user is logged in
 *   we need to make use of information stored in the Session object with keys "CURRENT_USER" 
 */




@SuppressWarnings("serial")
//Vaadin14,15,16
//public class LoggedInListener implements VaadinServiceInitListener {

//Only Vaadin 17
@Push(PushMode.MANUAL)

//Only for Vaadin 18 +
@Theme(value = Lumo.class)

public class LoggedInListener implements VaadinServiceInitListener, AppShellConfigurator {
	. . . . . . . . 

remember to remove the@Push and @Theme annotations from the main form!!!!