[ofbiz-framework] branch release18.12 updated: Improved: Replaces ModelInduceFromDb with widgets (OFBIZ-6510)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[ofbiz-framework] branch release18.12 updated: Improved: Replaces ModelInduceFromDb with widgets (OFBIZ-6510)

mbrohl
This is an automated email from the ASF dual-hosted git repository.

mbrohl pushed a commit to branch release18.12
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/release18.12 by this push:
     new 177b963  Improved: Replaces ModelInduceFromDb with widgets (OFBIZ-6510)
177b963 is described below

commit 177b96300fd0f8b3208cb67678faf732b73c4b2d
Author: Michael Brohl <[hidden email]>
AuthorDate: Thu Feb 11 21:12:26 2021 +0100

    Improved: Replaces ModelInduceFromDb with widgets (OFBIZ-6510)
   
    This is a manual backport of the related two commits in trunk with minor
    changes to fit the r18.12 codebase.
---
 .../java/org/apache/ofbiz/base/util/UtilXml.java   |  69 +++++++++-
 .../org/apache/ofbiz/entity/model/ModelEntity.java |  19 +++
 framework/webtools/config/WebtoolsUiLabels.xml     |  40 ++++++
 .../groovyScripts/entity/ModelInduceFromDb.groovy  |  20 +++
 .../apache/ofbiz/webtools/WebToolsDbEvents.java    | 141 +++++++++++++++++++++
 framework/webtools/template/Main.ftl               |   2 +-
 .../webtools/template/entity/EntityRefList.ftl     |   2 +-
 .../webtools/template/entity/ModelInduceFromDb.ftl |  59 +++++++++
 .../webapp/webtools/WEB-INF/controller.xml         |  17 ++-
 framework/webtools/widget/EntityScreens.xml        |  20 +++
 framework/webtools/widget/Menus.xml                |   4 +-
 11 files changed, 387 insertions(+), 6 deletions(-)

diff --git a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilXml.java b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilXml.java
index f23a709..097c6ed 100644
--- a/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilXml.java
+++ b/framework/base/src/main/java/org/apache/ofbiz/base/util/UtilXml.java
@@ -27,6 +27,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Reader;
+import java.io.StringWriter;
 import java.io.Writer;
 import java.net.URL;
 import java.util.LinkedList;
@@ -38,6 +39,7 @@ import java.util.regex.Pattern;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
@@ -55,6 +57,7 @@ import org.apache.xerces.xni.XMLLocator;
 import org.apache.xerces.xni.XMLResourceIdentifier;
 import org.apache.xerces.xni.XMLString;
 import org.apache.xerces.xni.XNIException;
+import org.w3c.dom.Comment;
 import org.w3c.dom.DOMConfiguration;
 import org.w3c.dom.Document;
 import org.w3c.dom.DocumentFragment;
@@ -1237,8 +1240,10 @@ public final class UtilXml {
 
     /**
      * get attribute value ignoring prefix in attribute name
+     *
      * @param element
-     * @return The value of the node, depending on its type; see the table Node class
+     * @return The value of the node, depending on its type; see the table Node
+     *         class
      */
     public static String getAttributeValueIgnorePrefix(Element element, String attributeName){
         if (element==null) {
@@ -1261,4 +1266,66 @@ public final class UtilXml {
         return "";
     }
 
+    public static String convertDocumentToXmlString(Document document) {
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer transformer;
+        try {
+            transformer = tf.newTransformer();
+            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+            StringWriter writer = new StringWriter();
+            transformer.transform(new DOMSource(document), new StreamResult(writer));
+            String output = writer.getBuffer().toString();
+            return output;
+        } catch (TransformerException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns an ASF Licence Header as a Comment Element
+     *
+     * @param document
+     * @return
+     */
+    public static Comment createApacheLicenceComment(Document document) {
+        String lb = "\n";
+
+        StringBuilder disclaimer = new StringBuilder();
+        disclaimer.append("Licensed to the Apache Software Foundation (ASF) under one");
+        disclaimer.append(lb);
+        disclaimer.append("or more contributor license agreements.  See the NOTICE file");
+        disclaimer.append(lb);
+        disclaimer.append("distributed with this work for additional information");
+        disclaimer.append(lb);
+        disclaimer.append("regarding copyright ownership.  The ASF licenses this file");
+        disclaimer.append(lb);
+        disclaimer.append("to you under the Apache License, Version 2.0 (the");
+        disclaimer.append(lb);
+        disclaimer.append("\"License\"); you may not use this file except in compliance");
+        disclaimer.append(lb);
+        disclaimer.append("with the License.  You may obtain a copy of the License at");
+        disclaimer.append(lb);
+        disclaimer.append(lb);
+        disclaimer.append("http://www.apache.org/licenses/LICENSE-2.0");
+        disclaimer.append(lb);
+        disclaimer.append(lb);
+        disclaimer.append("Unless required by applicable law or agreed to in writing,");
+        disclaimer.append(lb);
+        disclaimer.append("software distributed under the License is distributed on an");
+        disclaimer.append(lb);
+        disclaimer.append("\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY");
+        disclaimer.append(lb);
+        disclaimer.append("KIND, either express or implied.  See the License for the");
+        disclaimer.append(lb);
+        disclaimer.append("specific language governing permissions and limitations");
+        disclaimer.append(lb);
+        disclaimer.append("under the License.");
+        disclaimer.append(lb);
+
+        return document.createComment(disclaimer.toString());
+    }
 }
diff --git a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java
index 7f90885..c1a3cb1 100644
--- a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java
+++ b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java
@@ -1538,6 +1538,25 @@ public class ModelEntity implements Comparable<ModelEntity>, Serializable {
         return this.toXmlElement(document, this.getPackageName());
     }
 
+    public Element toGroupXmlElement(Document document) {
+        return this.toGroupXmlElement(document, this.getPackageName());
+    }
+
+    public Element toGroupXmlElement(Document document, String packageName) {
+        if (UtilValidate.isNotEmpty(this.getPackageName()) && !packageName.equals(this.getPackageName())) {
+            Debug.logWarning(
+                    "Export EntityModel XML Element [" + this.getEntityName() + "] with a NEW package - " + packageName,
+                    module);
+        }
+
+        Element root = document.createElement("entity-group");
+        root.setAttribute("group", packageName);
+
+        root.setAttribute("entity", this.getEntityName());
+
+        return root;
+    }
+
     /**
      * Writes entity model information in the Apple EOModelBundle format.
      *
diff --git a/framework/webtools/config/WebtoolsUiLabels.xml b/framework/webtools/config/WebtoolsUiLabels.xml
index 048ff06..57cf8a9 100644
--- a/framework/webtools/config/WebtoolsUiLabels.xml
+++ b/framework/webtools/config/WebtoolsUiLabels.xml
@@ -5989,4 +5989,44 @@
         <value xml:lang="de">Typ</value>
         <value xml:lang="en">Type</value>
     </property>
+    <property key="WebtoolsModelInduceFromDb">
+        <value xml:lang="de">Modell-XML aus der Datenbank indizieren</value>
+        <value xml:lang="en">Induce Model XML from Database</value>
+    </property>
+    <property key="ModelInduceDatasourceName">
+        <value xml:lang="de">Datenquelle</value>
+        <value xml:lang="en">Datasource</value>
+    </property>
+    <property key="ModelInduceEntityModel">
+        <value xml:lang="de">Entitäten Model</value>
+        <value xml:lang="en">Entity Model</value>
+    </property>
+    <property key="ModelInduceEntityGroup">
+        <value xml:lang="de">Entitäten Gruppe</value>
+        <value xml:lang="en">Entity Group</value>
+    </property>
+    <property key="ModelInduceInducedText">
+        <value xml:lang="de">Induzierter Text</value>
+        <value xml:lang="en">Induced Text</value>
+    </property>
+    <property key="ModelInducePackageName">
+        <value xml:lang="de">Packet Name</value>
+        <value xml:lang="en">Package Name</value>
+    </property>
+    <property key="ModelInduceInduceTypeError">
+        <value xml:lang="de">Bitte Induzierungs Typen auswählen.</value>
+        <value xml:lang="en">Please select an Induce Type.</value>
+    </property>
+    <property key="ModelInduceDatasourceNameError">
+        <value xml:lang="de">Name der Datenquelle benötigt.</value>
+        <value xml:lang="en">Datasource name required.</value>
+    </property>
+    <property key="ModelInduceEntityGroupError">
+        <value xml:lang="de">Für den Induzierungstyp "EntitätenGruppe" wird der Packet Name benötigt.</value>
+        <value xml:lang="en">Package name required for induce type entitygroup.</value>
+    </property>
+    <property key="ModelInduceDataStructureError">
+        <value xml:lang="de">Ermittlung der Datenstruktur fehlgeschlagen. Bitte gültige Datenquelle angeben.</value>
+        <value xml:lang="en">Could not determine Structure for this datasource. Please choose a valid datasource.</value>
+    </property>
 </resource>
diff --git a/framework/webtools/groovyScripts/entity/ModelInduceFromDb.groovy b/framework/webtools/groovyScripts/entity/ModelInduceFromDb.groovy
new file mode 100644
index 0000000..3c200d2
--- /dev/null
+++ b/framework/webtools/groovyScripts/entity/ModelInduceFromDb.groovy
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+context.inducedText = request.getAttribute("inducedText")
diff --git a/framework/webtools/src/main/java/org/apache/ofbiz/webtools/WebToolsDbEvents.java b/framework/webtools/src/main/java/org/apache/ofbiz/webtools/WebToolsDbEvents.java
new file mode 100644
index 0000000..dcf92d1
--- /dev/null
+++ b/framework/webtools/src/main/java/org/apache/ofbiz/webtools/WebToolsDbEvents.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.apache.ofbiz.webtools;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.ofbiz.base.util.UtilHttp;
+import org.apache.ofbiz.base.util.UtilMisc;
+import org.apache.ofbiz.base.util.UtilProperties;
+import org.apache.ofbiz.base.util.UtilValidate;
+import org.apache.ofbiz.base.util.UtilXml;
+import org.apache.ofbiz.entity.datasource.GenericDAO;
+import org.apache.ofbiz.entity.datasource.GenericHelperInfo;
+import org.apache.ofbiz.entity.model.ModelEntity;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class WebToolsDbEvents {
+    private static final String MODULE = WebToolsDbEvents.class.getName();
+    private static final String RESOURCE = "WebtoolsUiLabels";
+    private static Document document;
+    private static final String TITLE = "Entities of an Apache Open For Business Project (Apache OFBiz) Component";
+    private static final String DESCRIPTION = "None";
+    private static final String COPYRIGHT = String.format("Copyright 2001-%d The Apache Software Foundation",
+            LocalDate.now().getYear());
+    private static final String AUTHOR = "None";
+    private static final String VERSION = "1.0";
+    private static final String SEPARATOR = "=========================================================";
+    private static final String INTRO = "The modules in this file are as follows:";
+    private static final String DEFAULTS = "======================== Defaults =======================";
+    private static final String HEADER = "======================== Data Model =====================";
+    private static final String XMLN_NAME = "xmlns:xsi";
+    private static final String XMLN_VALUE = "http://www.w3.org/2001/XMLSchema-instance";
+    private static final String XSI_NAME = "xsi:noNamespaceSchemaLocation";
+    private static final String XSI_VALUE = "http://ofbiz.apache.org/dtds/entitymodel.xsd";
+
+    /**
+     * Indexes the Datasource defined in the entityengine.xml
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    public static String modelInduceFromDb(HttpServletRequest request, HttpServletResponse response) {
+        List<String> errorMessageList = new ArrayList<>();
+        Map<String, Object> params = UtilHttp.getParameterMap(request);
+        Locale locale = UtilHttp.getLocale(request);
+
+        String induceType = (String) params.get("induceType");
+        String datasourceName = (String) params.get("datasourceName");
+        String packageName = (String) params.get("packageName");
+
+        if (UtilValidate.isEmpty(induceType)) {
+            errorMessageList.add(UtilProperties.getMessage(RESOURCE, "ModelInduceInduceTypeError", locale));
+        }
+
+        if (UtilValidate.isEmpty(datasourceName)) {
+            errorMessageList.add(UtilProperties.getMessage(RESOURCE, "ModelInduceDatasourceNameError", locale));
+        }
+
+        if ("entitygroup".equals(induceType) && UtilValidate.isEmpty(packageName)) {
+            errorMessageList.add(UtilProperties.getMessage(RESOURCE, "ModelInduceEntityGroupError", locale));
+        }
+
+        if (UtilValidate.isNotEmpty(errorMessageList)) {
+            request.setAttribute("errorMessageList", errorMessageList);
+            return "error";
+        }
+
+        document = UtilXml.makeEmptyXmlDocument();
+
+        Element entitymodel = document.createElement("entitymodel");
+        entitymodel.setAttribute(XMLN_NAME, XMLN_VALUE);
+        entitymodel.setAttribute(XSI_NAME, XSI_VALUE);
+        Comment licenceDisclaimer = UtilXml.createApacheLicenceComment(document);
+        document.appendChild(licenceDisclaimer);
+        document.appendChild(entitymodel);
+
+        entitymodel.appendChild(document.createComment(SEPARATOR));
+        entitymodel.appendChild(document.createComment(DEFAULTS));
+        entitymodel.appendChild(document.createComment(SEPARATOR));
+
+        if ("entitymodel".equals(induceType)) {
+            UtilXml.addChildElementValue(entitymodel, "title", TITLE, document);
+            UtilXml.addChildElementValue(entitymodel, "description", DESCRIPTION, document);
+            UtilXml.addChildElementValue(entitymodel, "copyright", COPYRIGHT, document);
+            UtilXml.addChildElementValue(entitymodel, "author", AUTHOR, document);
+            UtilXml.addChildElementValue(entitymodel, "version", VERSION, document);
+
+            entitymodel
+                    .appendChild(document.createComment(SEPARATOR));
+            entitymodel
+                    .appendChild(document.createComment(HEADER));
+            entitymodel.appendChild(document.createComment(INTRO));
+            entitymodel
+                    .appendChild(document.createComment(SEPARATOR));
+        }
+        GenericDAO dao = GenericDAO.getGenericDAO(new GenericHelperInfo(null, datasourceName));
+        List<ModelEntity> newEntList = dao.induceModelFromDb(new ArrayList<String>());
+        if (UtilValidate.isEmpty(newEntList)) {
+            request.setAttribute("errorMessageList",
+                    UtilMisc.toList(UtilProperties.getMessage(RESOURCE, "ModelInduceDataStructureError", locale)));
+            return "error";
+        }
+
+        for (ModelEntity entity : newEntList) {
+            if ("entitymodel".equals(induceType)) {
+                entitymodel.appendChild(entity.toXmlElement(document, packageName));
+            } else {
+                entitymodel.appendChild(entity.toGroupXmlElement(document, packageName));
+            }
+        }
+
+        request.setAttribute("inducedText", UtilXml.convertDocumentToXmlString(document));
+        return "success";
+    }
+}
diff --git a/framework/webtools/template/Main.ftl b/framework/webtools/template/Main.ftl
index b9b8388..99b0d80 100644
--- a/framework/webtools/template/Main.ftl
+++ b/framework/webtools/template/Main.ftl
@@ -57,7 +57,7 @@ under the License.
           <li><a href="<@ofbizUrl>entityrefReport</@ofbizUrl>" target="_blank">${uiLabelMap.WebtoolsEntityReferencePdf}</a></li>
           <li><a href="<@ofbizUrl>EntitySQLProcessor</@ofbizUrl>">${uiLabelMap.PageTitleEntitySQLProcessor}</a></li>
           <li><a href="<@ofbizUrl>EntitySyncStatus</@ofbizUrl>">${uiLabelMap.WebtoolsEntitySyncStatus}</a></li>
-          <li><a href="<@ofbizUrl>view/ModelInduceFromDb</@ofbizUrl>" target="_blank">${uiLabelMap.WebtoolsInduceModelXMLFromDatabase}</a></li>
+          <li><a href="<@ofbizUrl>ModelInduceFromDb</@ofbizUrl>" target="_blank">${uiLabelMap.WebtoolsInduceModelXMLFromDatabase}</a></li>
           <li><a href="<@ofbizUrl>EntityEoModelBundle</@ofbizUrl>">${uiLabelMap.WebtoolsExportEntityEoModelBundle}</a></li>
           <li><a href="<@ofbizUrl>view/checkdb</@ofbizUrl>">${uiLabelMap.WebtoolsCheckUpdateDatabase}</a></li>
           <li><a href="<@ofbizUrl>ConnectionPoolStatus</@ofbizUrl>">${uiLabelMap.ConnectionPoolStatus}</a></li>
diff --git a/framework/webtools/template/entity/EntityRefList.ftl b/framework/webtools/template/entity/EntityRefList.ftl
index 1ace17f..c38b1f2 100644
--- a/framework/webtools/template/entity/EntityRefList.ftl
+++ b/framework/webtools/template/entity/EntityRefList.ftl
@@ -47,7 +47,7 @@ under the License.
                 <a href="<@ofbizUrl>ModelGroupWriter</@ofbizUrl>" target='_blank'>Generate Entity Group XML</a><br/>
                 <a href="<@ofbizUrl>ModelGroupWriter?savetofile=true</@ofbizUrl>" target='_blank'>Save Entity Group XML to File</a><br/>
                 -->
-                <a href="<@ofbizUrl>view/ModelInduceFromDb</@ofbizUrl>" target='_blank'>${uiLabelMap.WebtoolsInduceModelXMLFromDatabase}</a><br/>
+                <a href="<@ofbizUrl>ModelInduceFromDb</@ofbizUrl>" target='_blank'>${uiLabelMap.WebtoolsInduceModelXMLFromDatabase}</a><br/>
             </#if>
             <#if packageNames?has_content>
                 <hr />
diff --git a/framework/webtools/template/entity/ModelInduceFromDb.ftl b/framework/webtools/template/entity/ModelInduceFromDb.ftl
new file mode 100644
index 0000000..bb40ce6
--- /dev/null
+++ b/framework/webtools/template/entity/ModelInduceFromDb.ftl
@@ -0,0 +1,59 @@
+<#--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<div class="page-title"><span>${uiLabelMap.WebtoolsModelInduceFromDb}</span></div>
+<form class="basic-form" method="post" action="<@ofbizUrl>CreateModelInduceFromDb</@ofbizUrl>">
+    <table class="basic-table" cellspacing="0">
+        <tbody>
+            </tr>
+                <td class="label">
+                    <label>${uiLabelMap.ModelInduceDatasourceName}</label>
+                </td>
+                <td>
+                    <input type="text" name="datasourceName"/>
+                </td>
+            </tr>
+            <tr>
+                <td class="label">
+                    <label>${uiLabelMap.ModelInducePackageName}</label>
+                </td>
+                <td>
+                    <input type="text" name="packageName"/>
+                </td>
+            </tr>
+            <tr>
+                <td></td>
+                <td>
+                    <select name="induceType">
+                        <option value="entitymodel">${uiLabelMap.ModelInduceEntityModel}</option>
+                        <option value="entitygroup">${uiLabelMap.ModelInduceEntityGroup}</option>
+                    </select>
+                </td>
+            </tr>
+            <tr>
+                <td>
+                    <input type="submit" name="submitButton"/>
+                </td><td></td>
+            </tr>
+        </tbody>
+    </table>
+</form>
+</hr>
+<div>
+    <textarea cols="60" rows="50" name="${uiLabelMap.ModelInduceInducedText}">${inducedText!}</textarea>
+</div>
diff --git a/framework/webtools/webapp/webtools/WEB-INF/controller.xml b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
index 7a61f6d..e0a5304 100644
--- a/framework/webtools/webapp/webtools/WEB-INF/controller.xml
+++ b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
@@ -400,6 +400,20 @@ under the License.
         <response name="success" type="view" value="ConnectionPoolStatus"/>
     </request-map>
 
+    <!-- ModelInducedFromDb requests-->
+    <request-map uri="CreateModelInduceFromDb">
+        <security https="true" auth="true"/>
+        <event type="java" path="org.apache.ofbiz.webtools.WebToolsDbEvents" invoke="modelInduceFromDb"/>
+        <response name="success" type="view" value="ModelInduceFromDb"/>
+        <response name="error" type="view" value="ModelInduceFromDb"/>
+    </request-map>
+
+    <request-map uri="ModelInduceFromDb">
+        <security https="true" auth="true"/>
+        <response name="success" type="view" value="ModelInduceFromDb"/>
+        <response name="error" type="view" value="ModelInduceFromDb"/>
+    </request-map>
+
     <!-- Entity Export/Import requests -->
     <request-map uri="ProgramExport">
         <security https="true" auth="true"/>
@@ -596,7 +610,8 @@ under the License.
     <view-map name="dataMySql" page="template/entity/dataMySql.jsp"/>
     <view-map name="ModelWriter" page="template/entity/ModelWriter.jsp"/>
     <view-map name="ModelGroupWriter" page="template/entity/ModelGroupWriter.jsp"/>
-    <view-map name="ModelInduceFromDb" page="template/entity/ModelInduceFromDb.jsp"/>
+
+    <view-map name="ModelInduceFromDb" type="screen" page="component://webtools/widget/EntityScreens.xml#ModelInduceFromDb"/>
     <view-map name="EntityEoModelBundle" type="screen" page="component://webtools/widget/EntityScreens.xml#EntityEoModelBundle"/>
 
     <view-map name="checkdb" type="screen" page="component://webtools/widget/EntityScreens.xml#CheckDb"/>
diff --git a/framework/webtools/widget/EntityScreens.xml b/framework/webtools/widget/EntityScreens.xml
index 1eacdbc..c448fb1 100644
--- a/framework/webtools/widget/EntityScreens.xml
+++ b/framework/webtools/widget/EntityScreens.xml
@@ -478,6 +478,26 @@ under the License.
         </section>
     </screen>
 
+     <screen name="ModelInduceFromDb">
+        <section>
+            <actions>
+                <property-map resource="WebtoolsUiLabels" map-name="uiLabelMap" global="true"/>
+                <script location="component://webtools/groovyScripts/entity/ModelInduceFromDb.groovy"/>
+            </actions>
+            <widgets>
+                <decorator-screen name="CommonImportExportDecorator" location="${parameters.mainDecoratorLocation}">
+                    <decorator-section name="body">
+                        <screenlet>
+                            <platform-specific>
+                                <html><html-template location="component://webtools/template/entity/ModelInduceFromDb.ftl"/></html>
+                            </platform-specific>
+                        </screenlet>
+                    </decorator-section>
+                </decorator-screen>
+            </widgets>
+        </section>
+    </screen>
+
     <screen name="ConnectionPoolStatus">
         <section>
             <actions>
diff --git a/framework/webtools/widget/Menus.xml b/framework/webtools/widget/Menus.xml
index 0dab587..8fbc716 100644
--- a/framework/webtools/widget/Menus.xml
+++ b/framework/webtools/widget/Menus.xml
@@ -74,8 +74,8 @@ under the License.
         <menu-item name="data" title="${uiLabelMap.WebtoolsDataFileTools}">
             <link target="viewdatafile"/>
         </menu-item>
-        <menu-item name="modelInduceFromDb" title="${uiLabelMap.WebtoolsInduceModelXMLFromDatabase}">
-            <link target="view/ModelInduceFromDb"/>
+        <menu-item name="ModelInduceFromDb" title="${uiLabelMap.WebtoolsInduceModelXMLFromDatabase}">
+            <link target="ModelInduceFromDb"/>
         </menu-item>
         <menu-item name="entityEoModelBundle" title="${uiLabelMap.WebtoolsExportEntityEoModelBundle}">
             <link target="EntityEoModelBundle"/>