0. Introduction
To show formatted text Hilite is usedProgrammatic elements such as menus, form ... have pros and cons. Let us see the cons:
- Rather difficult to code
- More time invested in programming at first
- Prone to find unexpected errors as the system is not usually for this purpose.
- Usually, the project does not take the correct direction and should be abandoned.
- Requires a higher level of knowledge and skills.
- Testing should be more exigent as an error propagates to all modules. An error in a builder class creates errors in all elements.
- Version control is more exigent too.
But if we cross this desert, the promised land is available to us. The pros are:
- The programmatic elements are all very similar, so the user once knows how to use an element, gets used to the rest of elements.
- A meta language is created so that not so qualified programmers can build elements.
- Productivity increases.
- Quicker delivery.
So not everything in the garden is rosy.
The inspiration of this is in Primefaces Showcase.
The goals of this post are:
The primefaces Layout panel seems a good choice to dispose of our elements. The menu will be displayed on the Left (West) panel. The center panel is for the content and the rest of the panels are omitted.
To follow the primefaces example a "growl" element is included. The file is
tutorial01-menu.xhtml
Note the line
<p:panelMenu model="#{menuBean.model}"/>
for describing the menu.
Our design is this one
+-----------------+---------------------------+
| | Botton1 Button2 |
| MENU | CONTENT |
| | |
| (west panel) | (center panel) |
| | |
| | |
+-----------------+---------------------------+
Two buttons have been included to show how to change the contents of the menu programmatically
When clicking a button the menu should change
The key of this bean is the MenuModel that references the jsf menu to be displayed.
The @PostConstruct annotation is used to initialize the component. (In this case reads the config file from "config/menu.json" in the "src/main/resources" folder and creates the menu structure.
The readMenu method makes use of a helper class (MenuBeanReaderJSON)to read the configuration from a Json File. It is important to delegate to another class as the menu configuration may be saved in other formats (in the data base or other media) and this helper class is a candidate to be injected by Weld CDI.
The map structure tries to emulate the menu structure, so the name of the keys are copied from the xml attributes defined for a Primefaces menu (url, icon, command,update, ajax), other are for internal use (name, type)
To define the node type an enum type is created (MenuItemType)
In a future post, JBoss Weld CDI will enable us to define helper classes to load menu configurations from different media (database, plain text file etc) and we will try to inject the reader helper class to the MenuBean.
Note that Main menu and submenu are distinguished to build the menu tree structure.
Another helper class for managing Json Objects is JsonUtils
JsonUtils also uses FileUtils, let's see these classes.
In this post, the method to read a Json file into a map is used.
JsonUtils:
FileUtils:
Two Json files are used (in the "usr/main/resources/config" folder)
Right click on the file "tutorial01-menu.xhtml" and select Run As- Run On Server
and it is displayed
and after clicking in "Update Menu02" button
our menu has changed programmatically !
- Define a pom.xml file with needed dependencies.
- Design our page (xhtml file) using Layout panel
- Define a bean to map the structure of a menu (MenuBean)
- Define the menu structure in a json file
- Define a custom exception
- Define beans for handling some actions (MenuActionExample)
- Define a class to read this file and assign values to MenuBean.
1. Pom.xml
Two new dependencies are needed, one for json files (jackson) and the other one for using standard utilities in Java (Apache Commons)
Finally, the updated pom.xml file is
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 99 100 101 102 103 104 105 106 107 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.ximodante.jsf</groupId> <artifactId>JSFv01</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>JSFv01</name> <description>JSF 2.2 & CDI</description> <properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <!-- Servlet 3.1 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- To solve Tomcat problem : java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- JSF 2.2 API --> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-api</artifactId> <version>2.2.14</version> </dependency> <!-- JSF 2.2 Implementation --> <dependency> <groupId>com.sun.faces</groupId> <artifactId>jsf-impl</artifactId> <version>2.2.14</version> </dependency> <!-- Primefaces --> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>6.1</version> </dependency> <!-- Primefaces Themes --> <dependency> <groupId>org.primefaces.extensions</groupId> <artifactId>all-themes</artifactId> <version>1.0.8</version> <type>pom</type> </dependency> <!-- Weld CDI for Tomcat (does not fulfill all capabilities !!!) --> <dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-shaded</artifactId> <version>3.0.0.Final</version> </dependency> <!-- Validation API Optional --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.0.CR3</version> </dependency> <!-- Hibernate Bean Validator Optional --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.1.Final</version> </dependency> <!-- Lombok for setters and getters --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> </dependency> <!-- JSON --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency> <!-- Apache Commons Utils --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.6</version> </dependency> </dependencies> </project> |
2. Using Layout panel to design out page
The primefaces Layout panel seems a good choice to dispose of our elements. The menu will be displayed on the Left (West) panel. The center panel is for the content and the rest of the panels are omitted.Layout from Primefaces showcase |
tutorial01-menu.xhtml
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 | <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:p="http://primefaces.org/ui"> <h:head> </h:head> <h:body> <h:form> <p:layout fullPage="true"> <p:layoutUnit position="west" size="200" header="Left" resizable="true" closable="true" collapsible="true" effect="drop"> <p:growl id="messages" showDetail="false"/> <p:panelMenu id="menu01" model="#{menuBean.model}"/> </p:layoutUnit> <p:layoutUnit position="center"> Content panel <p:commandButton value="Update Menu02" id="menuupd02" actionListener="#{menuBean.readMenu(true,'config/menu02.json')}" icon="ui-icon-disk" update="menu01"/> <p:commandButton value="Update Menu" id="menuupd" actionListener="#{menuBean.readMenu(true,'config/menu.json')}" icon="ui-icon-disk" update="menu01"/> </p:layoutUnit> </p:layout> </h:form> </h:body> </html> |
Note the line
<p:panelMenu model="#{menuBean.model}"/>
for describing the menu.
Our design is this one
+-----------------+---------------------------+
| | Botton1 Button2 |
| MENU | CONTENT |
| | |
| (west panel) | (center panel) |
| | |
| | |
+-----------------+---------------------------+
Two buttons have been included to show how to change the contents of the menu programmatically
<p:commandButton value="Update Menu02" id="menuupd02" actionListener="#{menuBean.readMenu(true,'config/menu02.json')}" icon="ui-icon-disk" update="menu01"/> <p:commandButton value="Update Menu" id="menuupd" actionListener="#{menuBean.readMenu(true,'config/menu.json')}" icon="ui-icon-disk" update="menu01"/>Each button aims to a different file (menu.json and menu02.json) in the config folder where the structure of the menu is defined.
When clicking a button the menu should change
3. MenuBean class
The source code of this class is1 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 | package org.ximodante.jsf.menu; import java.io.IOException; import java.io.Serializable; import javax.annotation.PostConstruct; /******************************************************** * CAREFUL USE: import javax.faces.view.ViewScoped * DO NOT USE: import javax.bean.view.ViewScoped ********************************************************/ import javax.faces.view.ViewScoped; import javax.inject.Named; import org.primefaces.model.menu.DefaultMenuModel; import org.primefaces.model.menu.MenuModel; import lombok.Getter; /** * Implements the menui structure as a bean * If a bean does not imnnplements Serializable, Tomcat crashes * MenuModel is the attribute to implement the men structure * initialMenuConfig is the name of the file to read the initial menu structure * * @author Ximo Dante * */ @Named @ViewScoped public class MenuBean implements Serializable { private static final long serialVersionUID = 1L; private static final String initialMenuConfig="config/menu.json"; @Getter private MenuModel menuModel; @PostConstruct public void init() { readMenu(true, initialMenuConfig); } /** * Reads the menu structure from a Json file using a class for that purpose. * @param isRelativeToResourceFolder (if relative Paths are used to access the config file) * @param fileName (Name of the file where configuration is stored) */ public void readMenu(boolean isRelativeToResourceFolder, String fileName) { menuModel = new DefaultMenuModel(); System.out.println("MenuBean.readMenu(" + isRelativeToResourceFolder + "," + fileName + ")" ); try { new MenuBeanReaderJSON().readMenu(true, fileName, menuModel); } catch (IOException | MenuJsfException e) { e.printStackTrace(); } } } |
The key of this bean is the MenuModel that references the jsf menu to be displayed.
The @PostConstruct annotation is used to initialize the component. (In this case reads the config file from "config/menu.json" in the "src/main/resources" folder and creates the menu structure.
The readMenu method makes use of a helper class (MenuBeanReaderJSON)to read the configuration from a Json File. It is important to delegate to another class as the menu configuration may be saved in other formats (in the data base or other media) and this helper class is a candidate to be injected by Weld CDI.
4. The reader class MenuBeanReaderJSON
The objectives of this class are:- Read the content of the menu description file
- Load this content into a handy map structure
- Fill the MenuModel element using the map
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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | package org.ximodante.jsf.menu; import java.io.IOException; import java.util.ArrayList; import java.util.Map; import org.primefaces.model.menu.DefaultMenuItem; import org.primefaces.model.menu.DefaultSubMenu; import org.primefaces.model.menu.MenuModel; import org.ximodante.utils.json.JsonUtils; import org.ximodante.utils.menuOLD.MenuItemType; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; public class MenuBeanReaderJSON { /** * Reads the menu from a JSON object as a Map * @param isRelativeToResourceFolder * @param fileName * @param menu * @throws JsonParseException * @throws JsonMappingException * @throws IOException * @throws MenuJsfException */ public void readMenu (boolean isRelativeToResourceFolder, String fileName, MenuModel menu) throws JsonParseException, JsonMappingException, IOException, MenuJsfException { Map<String,Object> map=JsonUtils.readMap(true, fileName ); //getMenuFromMap(map, menu.getModel(), null, 0); getMenuFromMap(map, menu, null, 0); } /** * Transform a Map structure from a JSon object into a MenuModel o Submenu. * One and only one of either menu or submenu is null * @param map * @param menu * @param submenu * @throws MenuJsfException */ @SuppressWarnings("unchecked") private static void getMenuFromMap(Map<String,Object> map, MenuModel menu, DefaultSubMenu submenu, int level) throws MenuJsfException { String name = null; String command = null; String icon = null; String url = null; String update = null; Boolean ajax = null; MenuItemType type = MenuItemType.ITEM; // by default ArrayList<Map<String,Object>> list = null; // 0. Extract information from Map for(String s: map.keySet()) { switch (s) { case "name" : name =(String) map.get("name" ); break; case "command" : command=(String) map.get("command"); break; case "icon" : icon =(String) map.get("icon") ; break; case "url" : url =(String) map.get("url") ; break; case "update" : update =(String) map.get("update") ; break; case "ajax" : ajax =Boolean.valueOf((String) map.get("ajax")) ; break; case "type" : type =MenuItemType.valueOf((String) map.get("type")); break; case "elements" : list = (ArrayList<Map<String,Object>>) map.get("elements"); break; default: throw new MenuJsfException ("KEY: " + s + " is not allowed in 'menu.json' (only name, type, comand, icon, url, update, ajax, elements) "); } } // 1. Set default values // The first level is for main menu if (level==0) { if (name == null) name="main"; type = MenuItemType.MENU; } // if elements is not null it is of type submenu/menu if (level>0) { if (list != null) type = MenuItemType.SUBMENU; } // 2. Detect errors if (name == null) throw new MenuJsfException ("No Name in a menu item."); if(name.trim().compareToIgnoreCase("main")==0) { if (type != MenuItemType.MENU) throw new MenuJsfException ("menuitem.name='main' and it is not MENU type."); if (menu == null) throw new MenuJsfException ("menuitem.name='main' and MenuModel is NULL."); if (submenu!= null) throw new MenuJsfException ("menuitem.name='main' and DefaultSubMenu is NOT NULL."); } if(name.trim().compareToIgnoreCase("main")!=0) { if (type == MenuItemType.MENU) throw new MenuJsfException ("menuitem.name IS NOT 'main' and it is MENU type."); //if (menu != null) throw new MenuJsfException ("menuitem.name IS NOT 'main' and MenuModel is NOT NULL."); //if (submenu== null) throw new MenuJsfException ("menuitem.name IS NOT 'main' and DefaultSubMenu is NULL."); } if (type == MenuItemType.MENU || type == MenuItemType.SUBMENU) { if (command!= null) throw new MenuJsfException (type + " type and 'command' is NOT NULL."); if (icon != null) throw new MenuJsfException (type + " type and 'icon' is NOT NULL."); if (update != null) throw new MenuJsfException (type + " type and 'icon' is NOT NULL."); if (ajax != null) throw new MenuJsfException (type + " type and 'ajax' is NOT NULL."); } if (type == MenuItemType.ITEM && list !=null) throw new MenuJsfException ("Only MENU and SUBMENU types can have nested elements"); System.out.println(name + ' ' + type); // 3.1. MENU (Main) if (type == MenuItemType.MENU) { System.out.println("Defining Main Menu"); for (Map<String,Object> mapChild: list) { getMenuFromMap(mapChild, menu, null, level +1); } } // 3.2 SUBMENU if (type == MenuItemType.SUBMENU) { DefaultSubMenu sbMnu = new DefaultSubMenu(name); if (icon != null) sbMnu.setIcon (icon); System.out.println("Defining SubMenu->" + name); for (Map<String,Object> mapChild: list) { getMenuFromMap(mapChild, null, sbMnu, level +1); } if (menu !=null) menu.addElement(sbMnu); else submenu.addElement(sbMnu); } // 3.3 ITEM if (type == MenuItemType.ITEM) { DefaultMenuItem item = new DefaultMenuItem(name); if (url != null) item.setUrl (url); if (icon != null) item.setIcon (icon); if (command!= null) item.setCommand(command); if (update != null) item.setUpdate (update); if (ajax != null) item.setAjax (ajax); System.out.println("Defining item->" + name); if (menu !=null) menu.addElement(item); else submenu.addElement(item); } } /** public static void main(String[] args) { Map<String,Object> map =new HashMap<>(); map.put("name", "main"); String pp=(String)map.get("surname"); System.out.println(pp); pp=(String)map.get("name"); System.out.println(pp); // TODO Auto-generated method stub } */ } |
The map structure tries to emulate the menu structure, so the name of the keys are copied from the xml attributes defined for a Primefaces menu (url, icon, command,update, ajax), other are for internal use (name, type)
To define the node type an enum type is created (MenuItemType)
1 2 3 4 5 6 7 | package org.ximodante.jsf.menu; public enum MenuItemType { MENU, SUBMENU, ITEM; } |
In a future post, JBoss Weld CDI will enable us to define helper classes to load menu configurations from different media (database, plain text file etc) and we will try to inject the reader helper class to the MenuBean.
Note that Main menu and submenu are distinguished to build the menu tree structure.
Another helper class for managing Json Objects is JsonUtils
JsonUtils also uses FileUtils, let's see these classes.
5. JsonUtils & FileUtils
In this post, the method to read a Json file into a map is used.
JsonUtils:
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 99 100 101 102 103 104 105 106 107 | package org.ximodante.utils.json; import java.io.IOException; import java.util.Map; import org.ximodante.utils.file.FileUtils; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; public class JsonUtils { /** * Reads a json object and transforms it to the desired class * @param fileName Path of the file to read * @param clazz Class of the object to get * @return Object of that class "clazz" * @throws JsonParseException * @throws JsonMappingException * @throws IOException */ public static <T> T readObject (boolean isRelativeToResourceFolder, String fileName, Class<T> clazz ) throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(FileUtils.getFile(isRelativeToResourceFolder, fileName), clazz); } /** * Writes a JSON Object to a file * @param isRelativeToResourceFolder * @param fileName * @param obj * @throws JsonGenerationException * @throws JsonMappingException * @throws IOException */ public static <T> void writeObject (boolean isRelativeToResourceFolder, String fileName, T obj ) throws JsonGenerationException, JsonMappingException, IOException { ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(FileUtils.getFile(isRelativeToResourceFolder, fileName), obj);//Plain JSON } /** * Reads a JSON Object as a Map * @param isRelativeToResourceFolder * @param fileName * @return * @throws JsonParseException * @throws JsonMappingException * @throws IOException */ public static Map<String,Object> readMap (boolean isRelativeToResourceFolder, String fileName) throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = new ObjectMapper(); return mapper.readValue(FileUtils.getFile(isRelativeToResourceFolder, fileName), new TypeReference<Map<String, Object>>() { }); } /** * Writes a map to a file as a JSON Object * @param isRelativeToResourceFolder * @param fileName * @param map * @throws JsonParseException * @throws JsonMappingException * @throws IOException */ public static void writeMap (boolean isRelativeToResourceFolder, String fileName, Map<String,Object> map) throws JsonParseException, JsonMappingException, IOException { ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(FileUtils.getFile(isRelativeToResourceFolder, fileName), map);//Plain JSON } /** * * @param args */ /** public static void main(String[] args) { Prova prova= new Prova(); System.out.println(prova.camp1); System.out.println(prova.camp2); Prova prova1; try { writeObject(true,"prova1.json",prova); //PLAIN JSON; //ObjectMapper mapper = new ObjectMapper(); //mapper.writerWithDefaultPrettyPrinter().writeValue(new File("src/main/resources/prova2.json"), prova);//Prettified JSON prova1 =readObject(true, "prova.json", prova.getClass()); System.out.println(prova1 .camp1); System.out.println(prova1 .camp2); } catch (Exception e) { e.printStackTrace(); } // TODO Auto-generated method stub } */ } |
FileUtils:
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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | package org.ximodante.utils.file; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.stream.Stream; /** * * @author Ximo Dante * Reads the content of a file * */ public class FileUtils { public static final String RESOURCES_FOLDER = "src/main/resources"; public static final boolean IS_WEB = true; // If run on server /** * Gets a File Object pointing to a Path * <ol> * <li> If isRelativeToResourceFolder is TRUE, then PATH= usr/main/resources/ + fileName * <li> If isRelativeToResourceFolder is FALSE, then PATH= fileName * </ol> * * @see https://www.mkyong.com/java/java-read-a-file-from-resources-folder/ * @see http://www.baeldung.com/java-properties * * @param isRelativeToResourceFolder * @param fileName * * @return a File Object pointing to a path. */ private static String relativePath(String fileName) { String path=""; if (IS_WEB) { /* Mykong https://www.mkyong.com/java/java-read-a-file-from-resources-folder/ ClassLoader classLoader = new FileUtils().getClass().getClassLoader(); path = classLoader.getResource("").getFile() + fileName; */ // Baeldung http://www.baeldung.com/java-properties path = Thread.currentThread().getContextClassLoader().getResource("").getPath() + fileName; } else path= (RESOURCES_FOLDER + '/' + fileName).replaceAll("//", "/"); System.out.println("PATH=" + path); return path; } public static File getFile(boolean isRelativeToResourceFolder, String fileName) { if (isRelativeToResourceFolder) return new File(relativePath(fileName)); else return new File(fileName); } public static Path getPath(boolean isRelativeToResourceFolder, String fileName) { if (isRelativeToResourceFolder) return Paths.get(relativePath(fileName)); else return Paths.get(fileName); } /** * This method is only valid for small files as it is high memory consumer * @see http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ * @param isRelativeToResourceFolder if the fileName is relative to usr/main/resources folder * @param fileName * @return The content of file as a String * @throws IOException */ public static String readStrContent(boolean isRelativeToResourceFolder, String fileName) throws IOException { File file = getFile(isRelativeToResourceFolder,fileName); if (file.exists()) return new String(Files.readAllBytes(file.toPath())); else return "ERROR: File " + fileName + " does not exists!."; } /** * Writes a string to a file for creating a small file with the content of a string * @param isRelativeToResourceFolder * @param fileName * @param content * @throws IOException */ public static void writeStrContent(boolean isRelativeToResourceFolder, String fileName, String content) throws IOException { Files.write(getPath(isRelativeToResourceFolder, fileName), content.getBytes()); } /** * This method is only valid for small files as it is high memory consumer * @see http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ * @param isRelativeToResourceFolder if the fileName is relative to usr/main/resources folder * @param fileName * @return The content of file as a List<String> * @throws IOException */ public static List<String> readLstContent(boolean isRelativeToResourceFolder, String fileName) throws IOException { File file = getFile(isRelativeToResourceFolder,fileName); if (file.exists()) return Files.readAllLines(file.toPath()); else return null; } /** * Writes a List<String> to a file for creating a small file with the content of a List<String> * @see http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ * @param isRelativeToResourceFolder * @param fileName * @param content * @throws IOException */ public static void writeLstContent(boolean isRelativeToResourceFolder, String fileName, List<String> content) throws IOException { Files.write(getPath(isRelativeToResourceFolder,fileName), content); } /** * This method is valid for all files, and returns a Java Stream * @see http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ * @param isRelativeToResourceFolder if the fileName is relative to usr/main/resources folder * @param fileName * @return The content of file as a Stream<String> * @throws IOException */ public static Stream<String> readStrmContent(boolean isRelativeToResourceFolder, String fileName) throws IOException { File file = getFile(isRelativeToResourceFolder,fileName); if (file.exists()) return Files.lines(file.toPath()); else return null; } /** * Writes a Stream<String> to a file for creating a file with the content of a Stream<String> * @see http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ * @param isRelativeToResourceFolder * @param fileName * @param content * @throws IOException */ public static void writeStrmContent(boolean isRelativeToResourceFolder, String fileName, Stream<String> content) throws IOException { Files.write(getPath(isRelativeToResourceFolder,fileName), (Iterable<String>)content::iterator); } /** * This method is valid for all files, and returns a Buffered reader * @see http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ * @param isRelativeToResourceFolder if the fileName is relative to usr/main/resources folder * @param fileName * @return The content of file as a Stream<String> * @throws IOException */ public static BufferedReader readBufContent(boolean isRelativeToResourceFolder, String fileName) throws IOException { File file = getFile(isRelativeToResourceFolder,fileName); if (file.exists()) return Files.newBufferedReader(file.toPath()); else return null; } /** * Writes a String to a file for creating a file with the content of a String * @see http://winterbe.com/posts/2015/03/25/java8-examples-string-number-math-files/ * @param isRelativeToResourceFolder * @param fileName * @param content * @throws IOException */ public static void writeBufContent(boolean isRelativeToResourceFolder, String fileName, String content) throws IOException { BufferedWriter writer = Files.newBufferedWriter(getPath(isRelativeToResourceFolder,fileName)); writer.write(content); writer.close(); } /** * Examples of using these methods * @param args */ /** public static void main(String[] args) { try { String fileName="config/menu.json"; System.out.println("Reading file from 'src/main/resources/" + fileName); System.out.println("\nUSING readStrContent-----------------"); System.out.println(readStrContent(true, fileName)); System.out.println("\nUSING readLstContent-----------------"); readLstContent(true, fileName) .stream() .forEach(System.out::println); System.out.println("\nUSING readStrmContent-----------------"); readStrmContent(true, fileName) .forEach(System.out::println); System.out.println("\nUSING readBufContent-----------------"); readBufContent(true, fileName) .lines() .forEach(System.out::println); System.out.println("\n\n==========================================================="); fileName="kk/writeStrContent.txt"; System.out.println("\nWriting file to 'src/main/resources/" + fileName); System.out.println("USING writeStrContent-----------------"); writeStrContent(true, fileName,"Writing to "+ fileName); fileName="kk/writeLstContent.txt"; System.out.println("\nWriting file to 'src/main/java/" + fileName); System.out.println("USING writeLstContent-----------------"); List<String>lst = Arrays.asList("Writing to "+ fileName, "Writing to "+ fileName); writeLstContent(true, fileName,lst); fileName="kk/writeStrmContent.txt"; System.out.println("\nWriting file to 'src/main/java/" + fileName); System.out.println("USING writeStrmContent-----------------"); lst = Arrays.asList("Writing to "+ fileName, "Writing to "+ fileName); writeStrmContent(true, fileName,lst.stream()); fileName="kk/writeBufContent.txt"; System.out.println("\nWriting file to 'src/main/java/" + fileName); System.out.println("USING writeBufContent-----------------"); writeBufContent(true, fileName,"Writing to "+ fileName); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } */ } |
6. Json files for configuring the menu
Two Json files are used (in the "usr/main/resources/config" folder)
- menu.json
- menu02.json
menu.json is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | { "name" : "main", "elements": [ { "name": "Dynamic Submenu", "type": "SUBMENU", "elements" : [ { "name": "External021", "url": "http://www.primefaces.org", "icon": "ui-icon-home" } , { "name": "External022", "url": "http://www.primefaces.org", "icon": "ui-icon-home" } , { "name": "Dynamic Actions03", "type": "SUBMENU", "elements" : [ { "name": "Save03", "command": "#{menuActionExample.save}", "icon": "ui-icon-disk", "update": "messages" }, { "name": "Delete03","command": "#{menuActionExample.delete}", "icon": "ui-icon-close", "ajax": "false" }, { "name": "Dynamic Actions04", "type": "SUBMENU", "elements" : [ { "name": "Save04", "command": "#{menuActionExample.save}", "icon": "ui-icon-disk", "update": "messages" }, { "name": "Delete04","command": "#{menuActionExample.delete}", "icon": "ui-icon-close", "ajax": "false" } ] } ] } ] }, { "name": "Dynamic Actions", "elements" : [ { "name": "Save02", "command": "#{menuActionExample.save}", "icon": "ui-icon-disk", "update": "messages" }, { "name": "Delete02","command": "#{menuActionExample.delete}", "icon": "ui-icon-close", "ajax": "false" } ] } ] } |
and menu02.json is
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "name" : "main", "elements": [ { "name": "Submenu A", "type": "SUBMENU", "elements" : [ { "name": "ExternalA1", "url": "http://www.primefaces.org", "icon": "ui-icon-home" } , { "name": "ExternalA2", "url": "http://www.primefaces.org", "icon": "ui-icon-home" } ] }, { "name": "SubMenu B", "elements" : [ { "name": "Save B2", "command": "#{menuActionExample.save}", "icon": "ui-icon-disk", "update": "messages" }, { "name": "Delete B2","command": "#{menuActionExample.delete}", "icon": "ui-icon-close", "ajax": "false" } ] } ] } |
7. Project Structure
Two snapshots will help to realize the project structure.
8. Executing the template
Right click on the file "tutorial01-menu.xhtml" and select Run As- Run On Server
and it is displayed
and after clicking in "Update Menu02" button
our menu has changed programmatically !
No hay comentarios:
Publicar un comentario