IDEMPIERE-5012 org.idempiere.ui.zk.annotation.Form annotation (#944)

This commit is contained in:
hengsin 2021-10-23 21:11:49 +08:00 committed by GitHub
parent fe2b0bb966
commit 633c2e240f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 468 additions and 1 deletions

View File

@ -19,6 +19,7 @@ Export-Package: bsh,
bsh.servlet, bsh.servlet,
bsh.util, bsh.util,
com.akunagroup.uk.postcode, com.akunagroup.uk.postcode,
io.github.classgraph,
it.sauronsoftware.cron4j, it.sauronsoftware.cron4j,
org.adempiere.apps.graph, org.adempiere.apps.graph,
org.adempiere.base, org.adempiere.base,

View File

@ -65,6 +65,7 @@ Import-Package: com.google.common.annotations;version="30.1.1",
org.jfree.util, org.jfree.util,
org.osgi.framework;version="1.7.0", org.osgi.framework;version="1.7.0",
org.osgi.framework.wiring;version="1.2.0", org.osgi.framework.wiring;version="1.2.0",
org.osgi.service.component;version="1.4.0",
org.osgi.service.component.annotations;version="1.3.0", org.osgi.service.component.annotations;version="1.3.0",
org.osgi.service.event;version="1.3.0", org.osgi.service.event;version="1.3.0",
org.osgi.util.tracker;version="1.5.0", org.osgi.util.tracker;version="1.5.0",

View File

@ -5,4 +5,5 @@
<service> <service>
<provide interface="org.adempiere.webui.factory.IFormFactory"/> <provide interface="org.adempiere.webui.factory.IFormFactory"/>
</service> </service>
<property name="service.ranking" type="Integer" value="-1"/>
</scr:component> </scr:component>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.adempiere.webui.factory.DefaultScanBasedFormFactory">
<property name="service.ranking" type="Integer" value="0"/>
<service>
<provide interface="org.adempiere.webui.factory.IFormFactory"/>
</service>
<implementation class="org.adempiere.webui.factory.DefaultScanBasedFormFactory"/>
</scr:component>

View File

@ -53,6 +53,7 @@ import org.zkoss.zul.Timer;
* IDEMPIERE-3101 * IDEMPIERE-3101
* @author Carlos Ruiz - globalqss * @author Carlos Ruiz - globalqss
*/ */
@org.idempiere.ui.zk.annotation.Form
public class AddAuthorizationForm extends ADForm { public class AddAuthorizationForm extends ADForm {
/** /**
* *

View File

@ -40,6 +40,7 @@ import org.zkoss.zul.Vlayout;
* @author hengsin * @author hengsin
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class CompareCtxHelpSuggestion extends ADForm { public class CompareCtxHelpSuggestion extends ADForm {
private static final String NEW_VALUE = "newValue"; private static final String NEW_VALUE = "newValue";

View File

@ -36,6 +36,7 @@ import org.zkoss.zul.Vlayout;
* @author hengsin * @author hengsin
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class CompareFieldSuggestion extends ADForm { public class CompareFieldSuggestion extends ADForm {
private static final String NEW_VALUE = "newValue"; private static final String NEW_VALUE = "newValue";

View File

@ -57,6 +57,7 @@ import org.zkoss.zul.Space;
* IDEMPIERE-4782 * IDEMPIERE-4782
* @author Carlos Ruiz - globalqss - BX Service * @author Carlos Ruiz - globalqss - BX Service
*/ */
@org.idempiere.ui.zk.annotation.Form
public class MFARegisterForm extends ADForm { public class MFARegisterForm extends ADForm {
/** /**
* *

View File

@ -85,6 +85,7 @@ import static org.adempiere.webui.ClientInfo.*;
* *
* Contributor : Fabian Aguilar - OFBConsulting - Multiallocation * Contributor : Fabian Aguilar - OFBConsulting - Multiallocation
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VAllocation")
public class WAllocation extends Allocation public class WAllocation extends Allocation
implements IFormController, EventListener<Event>, WTableModelListener, ValueChangeListener implements IFormController, EventListener<Event>, WTableModelListener, ValueChangeListener
{ {

View File

@ -99,7 +99,7 @@ import org.zkoss.zul.impl.XulElement;
* @author Niraj Sohun * @author Niraj Sohun
* @date September 28, 2007 * @date September 28, 2007
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.ArchiveViewer")
public class WArchiveViewer extends Archive implements IFormController, EventListener<Event> public class WArchiveViewer extends Archive implements IFormController, EventListener<Event>
{ {
private static final String ONCLOSE_TIMESTAMP_ATTR = "onclose.timestamp"; private static final String ONCLOSE_TIMESTAMP_ATTR = "onclose.timestamp";

View File

@ -65,6 +65,7 @@ import org.zkoss.zul.Vbox;
* @author Jorg Janke * @author Jorg Janke
* @version $Id: VAttributeGrid.java,v 1.2 2006/07/30 00:51:28 jjanke Exp $ * @version $Id: VAttributeGrid.java,v 1.2 2006/07/30 00:51:28 jjanke Exp $
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VAttributeGrid")
public class WAttributeGrid extends ADForm implements EventListener<Event> public class WAttributeGrid extends ADForm implements EventListener<Event>
{ {
/** /**

View File

@ -85,6 +85,7 @@ import org.zkoss.zul.Vlayout;
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VBOMDrop")
public class WBOMDrop extends ADForm implements EventListener<Event>, ValueChangeListener public class WBOMDrop extends ADForm implements EventListener<Event>, ValueChangeListener
{ {
/** /**

View File

@ -67,6 +67,7 @@ import org.zkoss.zul.Separator;
* @author Andrew Kimball * @author Andrew Kimball
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VCharge")
public class WCharge extends Charge implements IFormController, EventListener<Event> public class WCharge extends Charge implements IFormController, EventListener<Event>
{ {
/** /**

View File

@ -49,6 +49,7 @@ import org.zkoss.zul.South;
* @author Elaine * @author Elaine
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class WCreateFromForm extends ADForm implements EventListener<Event>, WTableModelListener, DialogEvents public class WCreateFromForm extends ADForm implements EventListener<Event>, WTableModelListener, DialogEvents
{ {

View File

@ -59,6 +59,7 @@ import org.zkoss.zul.Center;
import org.zkoss.zul.North; import org.zkoss.zul.North;
import org.zkoss.zul.South; import org.zkoss.zul.South;
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VFactReconcile")
public class WFactReconcile extends FactReconcile public class WFactReconcile extends FactReconcile
implements IFormController, EventListener<Event>, WTableModelListener, ValueChangeListener{ implements IFormController, EventListener<Event>, WTableModelListener, ValueChangeListener{

View File

@ -75,6 +75,7 @@ import org.zkoss.zul.Vbox;
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VFileImport")
public class WFileImport extends ADForm implements EventListener<Event> public class WFileImport extends ADForm implements EventListener<Event>
{ {
/** /**

View File

@ -80,6 +80,7 @@ import org.zkoss.zul.South;
* Generate custom form window * Generate custom form window
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class WGenForm extends ADForm implements EventListener<Event>, WTableModelListener public class WGenForm extends ADForm implements EventListener<Event>, WTableModelListener
{ {
/** /**

View File

@ -52,6 +52,7 @@ import org.zkoss.zul.North;
* Generate Shipment (manual) view class * Generate Shipment (manual) view class
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VInOutGen")
public class WInOutGen extends InOutGen implements IFormController, EventListener<Event>, ValueChangeListener public class WInOutGen extends InOutGen implements IFormController, EventListener<Event>, ValueChangeListener
{ {
private WGenForm form; private WGenForm form;

View File

@ -52,6 +52,7 @@ import org.zkoss.zul.North;
* Generate Invoice (manual) view class * Generate Invoice (manual) view class
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VInvoiceGen")
public class WInvoiceGen extends InvoiceGen implements IFormController, EventListener<Event>, ValueChangeListener public class WInvoiceGen extends InvoiceGen implements IFormController, EventListener<Event>, ValueChangeListener
{ {
private WGenForm form; private WGenForm form;

View File

@ -78,6 +78,7 @@ import org.zkoss.zul.Vlayout;
* @author Jorg Janke * @author Jorg Janke
* @version $Id: VMatch.java,v 1.2 2006/07/30 00:51:28 jjanke Exp $ * @version $Id: VMatch.java,v 1.2 2006/07/30 00:51:28 jjanke Exp $
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VMatch")
public class WMatch extends Match public class WMatch extends Match
implements IFormController, EventListener<Event>, WTableModelListener implements IFormController, EventListener<Event>, WTableModelListener
{ {

View File

@ -55,6 +55,7 @@ import org.zkoss.zul.South;
* @author Jorg Janke * @author Jorg Janke
* @version $Id: VMerge.java,v 1.2 2006/07/30 00:51:28 jjanke Exp $ * @version $Id: VMerge.java,v 1.2 2006/07/30 00:51:28 jjanke Exp $
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VMerge")
public class WMerge extends Merge implements IFormController, EventListener<Event> public class WMerge extends Merge implements IFormController, EventListener<Event>
{ {
/** /**

View File

@ -86,6 +86,7 @@ import com.lowagie.text.pdf.PdfReader;
* Carlos Ruiz - GlobalQSS - FR 3132033 - Make payment export class configurable per bank * Carlos Ruiz - GlobalQSS - FR 3132033 - Make payment export class configurable per bank
* Markus Bozem: IDEMPIERE-1546 / IDEMPIERE-3286 * Markus Bozem: IDEMPIERE-1546 / IDEMPIERE-3286
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VPayPrint")
public class WPayPrint extends PayPrint implements IFormController, EventListener<Event>, ValueChangeListener public class WPayPrint extends PayPrint implements IFormController, EventListener<Event>, ValueChangeListener
{ {
private CustomForm form = new CustomForm(); private CustomForm form = new CustomForm();

View File

@ -90,6 +90,7 @@ import org.zkoss.zul.Space;
* @author Jorg Janke * @author Jorg Janke
* @version $Id: VPaySelect.java,v 1.3 2006/07/30 00:51:28 jjanke Exp $ * @version $Id: VPaySelect.java,v 1.3 2006/07/30 00:51:28 jjanke Exp $
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VPaySelect")
public class WPaySelect extends PaySelect public class WPaySelect extends PaySelect
implements IFormController, EventListener<Event>, WTableModelListener, IProcessUI, ValueChangeListener implements IFormController, EventListener<Event>, WTableModelListener, IProcessUI, ValueChangeListener
{ {

View File

@ -64,6 +64,7 @@ import org.zkoss.zul.Vbox;
* @author Carlos Ruiz - globalqss - bxservice * @author Carlos Ruiz - globalqss - bxservice
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class WPluginManager extends ADForm implements EventListener<Event> { public class WPluginManager extends ADForm implements EventListener<Event> {
/** /**
* *

View File

@ -30,6 +30,7 @@ import org.compiere.util.Util;
* @author hengsin * @author hengsin
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class WProcessParameter implements IFormController { public class WProcessParameter implements IFormController {
private WProcessParameterForm parameterForm = null; private WProcessParameterForm parameterForm = null;

View File

@ -74,6 +74,7 @@ import org.zkoss.zul.Separator;
import org.zkoss.zul.Vbox; import org.zkoss.zul.Vbox;
@org.idempiere.ui.zk.annotation.Form
public class WReportCustomization implements IFormController,EventListener<Event> { public class WReportCustomization implements IFormController,EventListener<Event> {
private CustomForm form = new CustomForm(); private CustomForm form = new CustomForm();

View File

@ -61,6 +61,7 @@ import org.zkoss.zul.South;
* @author Elaine * @author Elaine
* @date September 18, 2012 * @date September 18, 2012
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VResetPassword")
public class WResetPassword implements IFormController, EventListener<Event>, ValueChangeListener { public class WResetPassword implements IFormController, EventListener<Event>, ValueChangeListener {
private static final CLogger log = CLogger.getCLogger(WResetPassword.class); private static final CLogger log = CLogger.getCLogger(WResetPassword.class);

View File

@ -55,6 +55,7 @@ import org.zkoss.zul.Center;
* @author Andrew Kimball * @author Andrew Kimball
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VSQLProcess")
public class WSQLProcess extends ADForm implements EventListener<Event> public class WSQLProcess extends ADForm implements EventListener<Event>
{ {
/** /**

View File

@ -76,6 +76,7 @@ import org.zkoss.zul.Vbox;
* @author Carlos Ruiz * @author Carlos Ruiz
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VSetupWizard")
public class WSetupWizard extends SetupWizard implements IFormController, EventListener<Event> public class WSetupWizard extends SetupWizard implements IFormController, EventListener<Event>
{ {
private CustomForm form = null; private CustomForm form = null;

View File

@ -62,6 +62,7 @@ import org.zkoss.zul.Hbox;
* @author Elaine * @author Elaine
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class WStatementCreateFromBatch extends StatementCreateFromBatch implements IFormController, EventListener<Event> public class WStatementCreateFromBatch extends StatementCreateFromBatch implements IFormController, EventListener<Event>
{ {
private WCreateFromForm form; private WCreateFromForm form;

View File

@ -90,6 +90,7 @@ import org.zkoss.zul.West;
* @author Carlos Ruiz * @author Carlos Ruiz
* *
*/ */
@org.idempiere.ui.zk.annotation.Form
public class WTabEditor extends TabEditor implements IFormController, EventListener<Event>, ValueChangeListener public class WTabEditor extends TabEditor implements IFormController, EventListener<Event>, ValueChangeListener
{ {
// TODO: create messages Property, VisibleFields, NonVisibleField // TODO: create messages Property, VisibleFields, NonVisibleField

View File

@ -70,6 +70,7 @@ import org.zkoss.zul.Treecols;
import org.zkoss.zul.Treeitem; import org.zkoss.zul.Treeitem;
import org.zkoss.zul.West; import org.zkoss.zul.West;
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VTreeBOM")
public class WTreeBOM extends TreeBOM implements IFormController, EventListener<Event> { public class WTreeBOM extends TreeBOM implements IFormController, EventListener<Event> {
private int m_WindowNo = 0; private int m_WindowNo = 0;

View File

@ -68,6 +68,7 @@ import org.zkoss.zul.Treeitem;
* @author Jorg Janke (modify: Sergio Oropeza sergioropeza@gmail.com, soropeza@dcsla.com 06/03/2014) * @author Jorg Janke (modify: Sergio Oropeza sergioropeza@gmail.com, soropeza@dcsla.com 06/03/2014)
* @version $Id: VTreeMaintenance.java,v 1.3 2006/07/30 00:51:28 jjanke Exp $ * @version $Id: VTreeMaintenance.java,v 1.3 2006/07/30 00:51:28 jjanke Exp $
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VTreeMaintenance")
public class WTreeMaintenance extends TreeMaintenance implements IFormController, EventListener<Event> public class WTreeMaintenance extends TreeMaintenance implements IFormController, EventListener<Event>
{ {
private CustomForm form = new CustomForm(); private CustomForm form = new CustomForm();

View File

@ -63,6 +63,7 @@ import org.zkoss.zul.South;
* @author Jorg Janke * @author Jorg Janke
* @version $Id: VTrxMaterial.java,v 1.3 2006/07/30 00:51:28 jjanke Exp $ * @version $Id: VTrxMaterial.java,v 1.3 2006/07/30 00:51:28 jjanke Exp $
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VTrxMaterial")
public class WTrxMaterial extends TrxMaterial public class WTrxMaterial extends TrxMaterial
implements IFormController, EventListener<Event>, ValueChangeListener implements IFormController, EventListener<Event>, ValueChangeListener
{ {

View File

@ -3,6 +3,7 @@ package org.adempiere.webui.apps.graph;
import org.adempiere.webui.panel.ADForm; import org.adempiere.webui.panel.ADForm;
import org.compiere.model.MGoal; import org.compiere.model.MGoal;
@org.idempiere.ui.zk.annotation.Form(name = "org.adempiere.apps.graph.ViewPI")
public class WViewPI extends ADForm { public class WViewPI extends ADForm {
/** /**

View File

@ -68,6 +68,7 @@ import org.zkoss.zul.Vbox;
* @author Low Heng Sin * @author Low Heng Sin
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.wf.WFPanel")
public class WFEditor extends ADForm { public class WFEditor extends ADForm {
/** /**
* *

View File

@ -76,6 +76,7 @@ import org.zkoss.zul.Html;
* @author hengsin * @author hengsin
* *
*/ */
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.wf.WFActivity")
public class WWFActivity extends ADForm implements EventListener<Event> public class WWFActivity extends ADForm implements EventListener<Event>
{ {
/** /**

View File

@ -0,0 +1,46 @@
/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Contributors: *
* - hengsin *
**********************************************************************/
package org.adempiere.webui.factory;
import org.osgi.service.component.annotations.Component;
/**
*
* @author hengsin
*
*/
@Component(immediate = true, service = IFormFactory.class, property = {"service.ranking:Integer=0"})
public final class DefaultScanBasedFormFactory extends ScanBasedFormFactory {
public DefaultScanBasedFormFactory() {
}
@Override
protected String[] getPackages() {
return new String[] {"org.adempiere.webui.apps.form", "org.adempiere.webui.apps.graph", "org.adempiere.webui.apps.wf",
"org.adempiere.webui.panel"};
}
}

View File

@ -26,6 +26,8 @@ package org.adempiere.webui.factory;
import org.adempiere.base.IMappedByNameFactory; import org.adempiere.base.IMappedByNameFactory;
import org.adempiere.webui.panel.ADForm; import org.adempiere.webui.panel.ADForm;
import org.idempiere.ui.zk.annotation.Form;
import org.osgi.framework.BundleContext;
/** /**
* *
@ -33,4 +35,10 @@ import org.adempiere.webui.panel.ADForm;
* *
*/ */
public interface IMappedFormFactory extends IMappedByNameFactory<ADForm> { public interface IMappedFormFactory extends IMappedByNameFactory<ADForm> {
/**
* Scan packages for class with {@link Form} annotation and add mapping for it
* @param context
* @param packages
*/
public void scan(BundleContext context, String... packages);
} }

View File

@ -25,6 +25,11 @@
package org.adempiere.webui.factory; package org.adempiere.webui.factory;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.function.Supplier;
import java.util.logging.Level;
/** /**
* *
* @author matheus.marcelino * @author matheus.marcelino
@ -32,14 +37,26 @@ package org.adempiere.webui.factory;
*/ */
import org.adempiere.base.MappedByNameFactory; import org.adempiere.base.MappedByNameFactory;
import org.adempiere.webui.panel.ADForm; import org.adempiere.webui.panel.ADForm;
import org.adempiere.webui.panel.IFormController;
import org.compiere.util.CLogger;
import org.idempiere.ui.zk.annotation.Form;
import org.osgi.framework.BundleContext;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
import io.github.classgraph.AnnotationInfo;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult;
@Component(name = "org.adempiere.webui.factory.MappedFormFactory", @Component(name = "org.adempiere.webui.factory.MappedFormFactory",
immediate = true, immediate = true,
service = {IFormFactory.class, IMappedFormFactory.class}, service = {IFormFactory.class, IMappedFormFactory.class},
property = {"service.ranking:Integer=1"}) property = {"service.ranking:Integer=1"})
public class MappedFormFactory extends MappedByNameFactory<ADForm> implements IFormFactory, IMappedFormFactory { public class MappedFormFactory extends MappedByNameFactory<ADForm> implements IFormFactory, IMappedFormFactory {
private final static CLogger s_log = CLogger.getCLogger(MappedFormFactory.class);
public MappedFormFactory() { public MappedFormFactory() {
} }
@ -48,4 +65,69 @@ public class MappedFormFactory extends MappedByNameFactory<ADForm> implements IF
return newInstance(formName); return newInstance(formName);
} }
@Override
public void scan(BundleContext context, String... packages) {
ClassLoader classLoader = context.getBundle().adapt(BundleWiring.class).getClassLoader();
ClassGraph graph = new ClassGraph()
.enableAnnotationInfo()
.overrideClassLoaders(classLoader)
.disableNestedJarScanning()
.disableModuleScanning()
.acceptPackagesNonRecursive(packages);
try (ScanResult scanResult = graph.scan()) {
for (ClassInfo classInfo : scanResult.getClassesWithAnnotation(Form.class)) {
if (classInfo.isAbstract())
continue;
String className = classInfo.getName();
try {
Class<?> clazz = (Class<?>) classInfo.loadClass();
Constructor<?> constructor = clazz.getConstructor();
FormSupplier supplier = new FormSupplier(constructor);
AnnotationInfo annotationInfo = classInfo.getAnnotationInfo(Form.class);
String alternateName = null;
if (annotationInfo != null)
alternateName = (String) annotationInfo.getParameterValues().getValue("name");
addMapping(className, supplier);
if (alternateName != null)
addMapping(alternateName, supplier);
} catch (Exception e) {
if (s_log.isLoggable(Level.INFO))
s_log.log(Level.INFO, e.getMessage(), e);
}
}
}
}
private static final class FormSupplier implements Supplier<ADForm> {
private Constructor<?> constructor;
private FormSupplier(Constructor<?> constructor) {
this.constructor = constructor;
}
@Override
public ADForm get() {
ADForm form = null;
try {
Object formObject = constructor.newInstance();
if (formObject != null) {
if (formObject instanceof ADForm) {
form = (ADForm)formObject;
} else if (formObject instanceof IFormController) {
IFormController controller = (IFormController) formObject;
form = controller.getForm();
form.setICustomForm(controller);
}
}
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
s_log.log(Level.WARNING, e.getMessage(), e);
}
return form;
}
}
} }

View File

@ -0,0 +1,162 @@
/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Contributors: *
* - hengsin *
**********************************************************************/
package org.adempiere.webui.factory;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import org.adempiere.webui.panel.ADForm;
import org.adempiere.webui.panel.IFormController;
import org.compiere.util.CLogger;
import org.compiere.util.Util;
import org.idempiere.ui.zk.annotation.Form;
import org.osgi.framework.BundleContext;
import org.osgi.framework.wiring.BundleWiring;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import io.github.classgraph.AnnotationInfo;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ClassInfo;
import io.github.classgraph.ScanResult;
/**
* Scan, discover and regiser classes with {@link Form} annotation.
* @author hengsin
*
*/
public abstract class ScanBasedFormFactory implements IFormFactory {
private final Map<String, String> classCache = new HashMap<>();
private final Map<String, Constructor<?>[]> constructorCache = new ConcurrentHashMap<>();
private BundleContext bundleContext = null;
private static final CLogger s_log = CLogger.getCLogger(ScanBasedFormFactory.class);
public ScanBasedFormFactory() {
}
@Override
public ADForm newFormInstance(String formName) {
ADForm form = null;
String realClassName = classCache.get(formName);
if (realClassName != null) {
Constructor<?> constructor = getConstructor(formName);
try {
Object formObject = constructor.newInstance();
if (formObject != null) {
if (formObject instanceof ADForm) {
form = (ADForm)formObject;
} else if (formObject instanceof IFormController) {
IFormController controller = (IFormController) formObject;
form = controller.getForm();
form.setICustomForm(controller);
}
}
} catch (Exception e) {
s_log.log(Level.WARNING, e.getMessage(), e);
}
if (form == null)
constructorCache.put(realClassName, new Constructor<?>[0]);
}
return form;
}
/**
*
* @param formName
* @return class default constructor
*/
public Constructor<?> getConstructor(String formName) {
String className = classCache.get(formName);
Constructor<?>[] constructors = null;
if (className != null) {
constructors = constructorCache.get(className);
if (constructors == null) {
ClassLoader classLoader = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
try {
Class<?> clazz = classLoader.loadClass(className);
Constructor<?> constructor = clazz.getDeclaredConstructor();
if (constructor != null) {
constructors = new Constructor<?>[] {constructor};
} else {
constructors = new Constructor<?>[0];
}
constructorCache.put(className, constructors);
} catch (Exception e) {
s_log.log(Level.WARNING, e.getMessage(), e);
constructors = new Constructor<?>[0];
constructorCache.put(className, constructors);
}
}
}
if (constructors != null && constructors.length == 1) {
return constructors[0];
} else {
return null;
}
}
protected abstract String[] getPackages();
@Activate
public void activate(ComponentContext context) throws ClassNotFoundException {
long start = System.currentTimeMillis();
bundleContext = context.getBundleContext();
ClassLoader classLoader = bundleContext.getBundle().adapt(BundleWiring.class).getClassLoader();
ClassGraph graph = new ClassGraph()
.enableAnnotationInfo()
.overrideClassLoaders(classLoader)
.disableNestedJarScanning()
.disableModuleScanning()
.acceptPackagesNonRecursive(getPackages());
try (ScanResult scanResult = graph.scan())
{
for (ClassInfo classInfo : scanResult.getClassesWithAnnotation(Form.class)) {
if (classInfo.isAbstract())
continue;
String className = classInfo.getName();
AnnotationInfo annotationInfo = classInfo.getAnnotationInfo(Form.class);
String alternateName = (String) annotationInfo.getParameterValues().getValue("name");
classCache.put(className, className);
if (!Util.isEmpty(alternateName, true))
classCache.put(alternateName, className);
}
}
long end = System.currentTimeMillis();
if (s_log.isLoggable(Level.INFO))
s_log.info(this.getClass().getSimpleName() + " loaded "+classCache.size() +" classes in "
+((end-start)/1000f) + "s");
}
}

View File

@ -1,5 +1,6 @@
package org.adempiere.webui.panel; package org.adempiere.webui.panel;
@org.idempiere.ui.zk.annotation.Form
public class CustomForm extends ADForm public class CustomForm extends ADForm
{ {

View File

@ -42,6 +42,7 @@ import org.zkoss.zul.Hbox;
import org.zkoss.zul.Html; import org.zkoss.zul.Html;
import org.zkoss.zul.Vlayout; import org.zkoss.zul.Vlayout;
@org.idempiere.ui.zk.annotation.Form
public class WProcessParameterForm extends ADForm public class WProcessParameterForm extends ADForm
{ {
/** /**

View File

@ -16,6 +16,7 @@ package org.adempiere.webui.panel;
import org.adempiere.webui.apps.form.WTabEditor; import org.adempiere.webui.apps.form.WTabEditor;
@org.idempiere.ui.zk.annotation.Form
public class WTabEditorForm extends ADForm public class WTabEditorForm extends ADForm
{ {
/** /**

View File

@ -0,0 +1,47 @@
/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Contributors: *
* - hengsin *
**********************************************************************/
package org.idempiere.ui.zk.annotation;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(ElementType.TYPE)
/**
* Annotation for web ui form
* @author hengsin
*
*/
public @interface Form {
/**
* Optional alternate name for form (in addition to class name)
* @return alternate name
*/
String name() default "String";
}

View File

@ -0,0 +1,76 @@
/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Contributors: *
* - hengsin *
**********************************************************************/
package org.idempiere.test.model;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.lang.reflect.Constructor;
import java.util.List;
import org.adempiere.base.IServiceReferenceHolder;
import org.adempiere.base.Service;
import org.adempiere.webui.factory.DefaultScanBasedFormFactory;
import org.adempiere.webui.factory.IFormFactory;
import org.compiere.model.MForm;
import org.compiere.model.Query;
import org.compiere.util.Env;
import org.idempiere.test.AbstractTestCase;
import org.junit.jupiter.api.Test;
/**
*
* @author hengsin
*
*/
public class FormTest extends AbstractTestCase {
public FormTest() {
}
@Test
public void testCoreFormMapping() {
DefaultScanBasedFormFactory formFactory = null;
List<IServiceReferenceHolder<IFormFactory>> factories = Service.locator().list(IFormFactory.class).getServiceReferences();
if (factories != null) {
for(IServiceReferenceHolder<IFormFactory> factory : factories) {
IFormFactory service = factory.getService();
if (service != null && service instanceof DefaultScanBasedFormFactory) {
formFactory = (DefaultScanBasedFormFactory) service;
break;
}
}
}
assertNotNull(formFactory, "Failed to locate DefaultScanBasedFormFactory");
Query query = new Query(Env.getCtx(), MForm.Table_Name, "AD_Form_ID < 1000000 AND ClassName IS NOT NULL "
+ " AND EXISTS (select 1 from ad_menu where isactive='Y' and ad_form_id=ad_form.ad_form_id)", getTrxName());
List<MForm> forms = query.setOnlyActiveRecords(true).list();
for (MForm form : forms) {
Constructor<?> constructor = formFactory.getConstructor(form.getClassname());
assertNotNull(constructor, "Failed to find class for " + form.toString() + ", " + form.getClassname());
}
}
}