Adempiere 380 Webui doesn't show popup for process error message and on complete error messages - adempiere

I am using adempiere 380 webui, i would like to show error message on any failure of adempiere process or onComplete of any document.
The code which i have written to show error popup working in desktop application. But in webui - jboss it printing in console of jboss.
I have accomplished this using AbstractADWindowPanel.java where i am checking process id or table then execute particular code in that and if error codition is true then i am displaying FDialog.ask("Print Message"); .
Is there any generic way to do this by which it can be used for all classes.

Since processes can be fully automated and run on the server, your code needs to be aware of the GUI being used so that the correct dialog script can be called. There are three options, a server process (no dialog), swing (ADialog) or ZK (FDialog). Generally, its discouraged to use dialogs in this way. Certainly, you wouldn't want a server process to block waiting for user input. But, if you know what your doing and really need to...
In the most recent releases, the process code includes a flag that tests which of the states its in so it can display errors. An example of how this is used is with the Migration Script saves to XML format. In the process, the GUI info is used to open the correct file dialog in swing or, in ZK, pass the request to the browser.
Here is a snippet of how it works from ProcessInfo.java in the current release
/**
* Get the interface type this process is being run from. The interface type
* can be used by the process to perform UI type actions from within the process
* or in the {#link #postProcess(boolean)}
* #return The InterfaceType which will be one of
* <li> {#link #INTERFACE_TYPE_NOT_SET}
* <li> {#link #INTERFACE_TYPE_SWING} or
* <li> {#link #INTERFACE_TYPE_ZK}
*/
public String getInterfaceType() {
if (interfaceType == null || interfaceType.isEmpty())
interfaceType = INTERFACE_TYPE_NOT_SET;
return interfaceType;
}
/**
* Sets the Interface Type
* #param uiType which must equal one of the following:
* <li> {#link #INTERFACE_TYPE_NOT_SET} (default)
* <li> {#link #INTERFACE_TYPE_SWING} or
* <li> {#link #INTERFACE_TYPE_ZK}
* The interface should be set by UI dialogs that start the process.
* #throws IllegalArgumentException if the interfaceType is not recognized.
*/
public void setInterfaceType(String uiType) {
// Limit value to known types
if (uiType.equals(INTERFACE_TYPE_NOT_SET)
||uiType.equals(INTERFACE_TYPE_ZK)
||uiType.equals(INTERFACE_TYPE_SWING) )
{
this.interfaceType = uiType;
}
else
{
throw new IllegalArgumentException("Unknown interface type " + uiType);
}
}
The call to setInterfaceType() is made when the process is launched by the ProcessModalDialog in swing or the AbstractZKForm or ProcessPanel in zk.
For other processes, the value is set by the AbstractFormController which is used by both interfaces. If the interface type is not set the loadProcessInfo method will try to figure it out as follows:
// Determine the interface type being used. Its set explicitly in the ProcessInfo data
// but we will fallback to testing the stack trace in case it wasn't. Note that the
// stack trace test may not be accurate as it depends on the calling class names.
// TODO Also note that we are only testing for ZK or Swing. If another UI is added, we'll
// have to fix this logic.
if (processInfo == null || processInfo.getInterfaceType().equals(ProcessInfo.INTERFACE_TYPE_NOT_SET))
{
// Need to know which interface is being used as the events may be different and the proper
// listeners have to be activated. Test the calling stack trace for "webui".
// If not found, assume the SWING interface
isSwing = true;
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
for (int i=1; i<stElements.length; i++) {
StackTraceElement ste = stElements[i];
if (ste.getClassName().contains("webui")
|| ste.getClassName().contains("zk.ui")) {
isSwing = false;
break;
}
}
log.warning("Process Info is null or interface type is not set. Testing isSwing = " + isSwing);
}
else
{
isSwing = processInfo.getInterfaceType().equals(ProcessInfo.INTERFACE_TYPE_SWING);
}
Finally, this can be used to control the dialogs within your process with a call similar to
if (ProcessInfo.INTERFACE_TYPE_SWING.equals(this.getProcessInfo().getInterfaceType()))
{
... Do something on a swing...
}
else ...

Related

Where do the Context fit between the GridField and the GridTab in Idempiere/Adempiere

I m trying to grasp the purpose of the following 3 concepts ( classes ) that are core functionalities in Idempiere/Adempiere.
Based on code description
I do understand that GridTab have the state of the model representing the ad_tab which is the ViewModel Part of any ad_table. simple said we will found the data bound to the ad_table.
First, for the GridField I believe is the model of the view, if I can abuse it is like the the DOM state: what do we have as fields, values of fields and events, I believe that is template view centric.
Dicovering this two ( if I m not mistaken in my analyses ) made me wonder. What do really the Ctx stands for? what state is it representing ?
The code is not commenting on this , can any body answer me?
Thanks .
In iDempiere the context is a Properties object that is global to the whole application.
You can think about the context as a global set of variables that you can access from any point of the system.
The context variables can be viewed clicking on the iDempiere icon, then navigating to the Errors tab, and then clicking on the View button, you'll find there the variables after the line:
=== Context ===
Within the context you can find a lot of information:
Login variables: some of those starting with #, like #AD_Role_ID
Defaults: records that are marked as default, also starting with #, like #C_BP_Group_ID
Accounting related variables: those starting with $, like $C_Currency_ID
Global Preferences: starting with P like P|AutoCommit
Window Preferences: starting with P and a number, example P132|GL_Category_ID
And then, the context variables that you're interested in, the value of each field on the windows that are open:
Window fields: those starting with a number, like 1|DiscountSchema - this means the field DiscountSchema in the first window opened
Tab fields: those starting with two numbers, like 1|2|DatePromised - this means the field DatePromised in the third tab (the number 2, tabs are numbered from zero) of the first window opened (the number 1)
You can access those context variables using Env.getContext... methods, and you can also add and delete your own variables with methods Env.setContext...
The use and intent of Context in ADempiere is the same as described by Carlos except for the access. In the web you can access the context from the top right of the window as shown below.
Another example of how the context provides global state is in testing. Here is a snippet from a test setup class that initializes the context with the time and login information. The context can then be accessed by test classes performing integration tests with a database as if they were in actual use. The context here is limited to login information but it could be extended to include any other element of the context required for the tests.
#BeforeAll
public static void setUpBeforeClass() {
today = TimeUtil.getDay(System.currentTimeMillis());
ctx = Env.getCtx();
ctx.setProperty("#AD_Org_ID", Integer.toString(AD_ORG_ID));
ctx.setProperty("#AD_User_ID", Integer.toString(AD_USER_ID));
ctx.setProperty("#AD_Client_ID", Integer.toString(AD_CLIENT_ID));
ctx.setProperty("#Date", TimeUtil.getDay(System.currentTimeMillis()).toString());
ctx.setProperty("#AD_Language", "en");
Ini.setClient (IS_CLIENT);
Ini.loadProperties(false);
org.compiere.Adempiere.startup(IS_CLIENT);
trxName = Trx.createTrxName("TestRun_" + randomString(4));
trx = Trx.get(trxName, false);
try {
mainSavepoint = trx.setSavepoint("AllTests_" + randomString(4));
} catch (SQLException e) {
fail(e.getMessage());
}
}
#AfterAll
public static void tearDownAfterClass() {
try {
tryToRollback(mainSavepoint);
trx.close();
}
catch(SQLException e) {
fail("Unable to rollback. " + e.getMessage());
}
finally {
trx.close();
trx = null;
ctx = null;
}
}

How to track java method calls and get alerts in Dynatrace?

I have a code similar to the one below. Every-time a DBLock appears, I want to get an alert in Dynatrace creating a problem so that I can see it on the dashboard and possibly get an email notification also. The DB lock would appear if the update count is greater than 1.
private int removeDBLock(DataSource dataSource) {
int updateCount = 0;
final Timestamp lastAllowedDBLockTime = new Timestamp(System.currentTimeMillis() - (5 * 60 * 1000));
final String query = format(RELEASE_DB_CHANGELOCK, lastAllowedDBLockTime.toString());
try (Statement stmt = dataSource.getConnection().createStatement()) {
updateCount = stmt.executeUpdate(query);
if(updateCount>0){
log.error("Stale DB Lock found. Locks Removed Count is {} .",updateCount);
}
} catch (SQLException e) {
log.error("Error while trying to find and remove Db Change Lock. ",e);
}
return updateCount;
}
I tried using the event API to trigger an event on my host mentioned here and was successful in raising a problem alert on my dashboard.
https://www.dynatrace.com/support/help/dynatrace-api/environment-api/events/post-event/?request-parameters%3C-%3Ejson-model=json-model
but this would mean injecting an api call in my code just for monitoring, any may lead to more external dependencies and hence more chance of failure.
I also tried creating a custom service detection by adding the class containing this method and the method itself in the custom service. But I do not know how I can link this to an alert or a event that creates a problem on the dashboard.
Are there any best practices or solutions on how I can do this in Dynatrace. Any leads would be helpful.
I would take a look at Custom Services for Java which will cause invocations of the method to be monitored in more detail.
Maybe you can extract a method which actually throws the exception and the outer method which handles it. Then it should be possible to alert on the exception.
There are also some more ways to configure the service via settings, i.e. raise an error based on a return value directly.
See also documentation:
https://www.dynatrace.com/support/help/how-to-use-dynatrace/transactions-and-services/configuration/define-custom-services/
https://www.dynatrace.com/support/help/technology-support/application-software/java/configuration-and-analysis/define-custom-java-services/

Is there a way to easily only allow a subset of azure functions to run when debugging locally in Visual Studio?

I'm using Visual Studio to write a class library which contains several Azure functions. There is a combination of timer and queue triggered functions. If I'm working on one of the functions and want to debug only it I have to comment out the other functions to keep them also from executing. Is there a way to easily indicate that I only want a subset of the entire set of functions to execute when debugging locally?
You can configure which functions to load in your host.json (full spec here.) Specifically, you'll want to define a top-level functions property:
{
"functions": [ "QueueProcessor", "GitHubWebHook" ]
}
(Note this is only meant for local use; you'll want to use the function.json disabled property for published functions.)
You could make use of the Disable() attribute, however, that's not much better than commenting out code:
public static void Run([TimerTrigger("0 */5 * * * *"), Disable()]TimerInfo myTimer, TraceWriter log)
You could combine the Disable() attribute with #if directive, but it clutters up your code. The Disable() attribute will only be applied if DEBUG is defined.
The following function will run if in release mode, and is disabled if in debug mode.
[FunctionName("TimerFunction")]
public static void Run([
#if DEBUG
TimerTrigger("*/5 * * * * *"), Disable()
#else
TimerTrigger("*/5 * * * * *")
#endif
]TimerInfo myTimer, TraceWriter log)
{
log.Info($"C# Timer trigger function executed at: {DateTime.Now}");
}
You can decorate your function with a DisableAttribute controlled by a settingName from the local.settings.json file.
The following is an example:
[QueueTrigger("%queueName%", Connection = "queues"), Disable("MyFuncABC")]ProcessMessage msg,

Rendering ClientBehaviorHolder

I am busy writing my own JSF2 UIComponents and their relevant renderers. All of my UIComponents implements ClientBehaviorHolder. What I don't understand is how to really render ClientBehaviorHolder.
For example, the following code illustrates how ClientBehaviorHolder is rendered in Mojarra.
private static void renderHandler(FacesContext context,
UIComponent component,
Collection<ClientBehaviorContext.Parameter> params,
String handlerName,
Object handlerValue,
String behaviorEventName,
String submitTarget,
boolean needsSubmit,
boolean includeExec)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
String userHandler = getNonEmptyUserHandler(handlerValue);
List<ClientBehavior> behaviors = getClientBehaviors(component, behaviorEventName);
// Don't render behavior scripts if component is disabled
if ((null != behaviors) &&
(behaviors.size() > 0) &&
Util.componentIsDisabled(component)) {
behaviors = null;
}
if (params == null) {
params = Collections.emptyList();
}
String handler = null;
switch (getHandlerType(behaviors, params, userHandler, needsSubmit, includeExec)) {
case USER_HANDLER_ONLY:
handler = userHandler;
break;
case SINGLE_BEHAVIOR_ONLY:
handler = getSingleBehaviorHandler(context,
component,
behaviors.get(0),
params,
behaviorEventName,
submitTarget,
needsSubmit);
break;
case SUBMIT_ONLY:
handler = getSubmitHandler(context,
component,
params,
submitTarget,
true);
break;
case CHAIN:
handler = getChainedHandler(context,
component,
behaviors,
params,
behaviorEventName,
userHandler,
submitTarget,
needsSubmit);
break;
default:
assert(false);
}
writer.writeAttribute(handlerName, handler, null);
}
For submit handlers, Mojarra adds the mojarra.jsfcljs javascript, UIParameters and other scripts. For chain handlers, jsf.util.chain is used.
My question is:
How does one determine if we have to render handlers in chain or a single behaviour or user specific handler?
mojarra.jsfcljs is only unique to Mojarra. PrimeFaces have their own implementation, so does Apache Tomahawk. Question is: what does mojarra.jsfcljs do and what is its use? This is so that I can write one for my own? Also, where can I find the implementation of mojarra.jsfcljs?
What is the specification to render ClientBehaviorHolder?
My sincere thanks in advance.
How does one determine if we have to render handlers in chain or a single behaviour or user specific handler?
Imagine that the enduser (read: the JSF developer who's using your component) programmed:
<your:component onclick="return foo()" />
And you intented to ultimately render for your component's own purpose:
<someHtmlElement onclick="jsf.ajax.request(...); return false;" />
Then you can't just concatenate the enduser's onclick in front of your component's jsf.ajax.request() like so
<someHtmlElement onclick="return foo(); jsf.ajax.request(...); return false;" />
Even if it returned true, your component's jsf.ajax.request won't be invoked at all. You ultimately want to end up something like:
<someHtmlElement onclick="if returnsTrue('return foo();') { jsf.ajax.request(...); } return false;" />
That's exactly what jsf.util.chain() is doing under the covers.
mojarra.jsfcljs is only unique to Mojarra. PrimeFaces have their own implementation, so does Apache Tomahawk. Question is: what does mojarra.jsfcljs do and what is its use? This is so that I can write one for my own? Also, where can I find the implementation of mojarra.jsfcljs?
It's inside the jsf.js file. Easy way to find it is to open a JSF page with <f:ajax> embedded and look in the generated <head> source for the <script> with its URL. This file is by default minified. If you set javax.faces.PROJECT_STAGE context param to Development, then this will be served unminified. The task of the jsfcljs() function is to submit the parent form with the necessary parameters. Here's an extract of relevance coming from Mojarra 2.1.21.
/*
* This is called by command link and command button. It provides
* the form it is nested in, the parameters that need to be
* added and finally, the target of the action. This function
* will delete any parameters added <em>after</em> the form
* has been submitted to handle DOM caching issues.
*
* #param f - the target form
* #param pvp - associative array of parameter
* key/value pairs to be added to the form as hidden input
* fields.
* #param t - the target of the form submission
*/
mojarra.jsfcljs = function jsfcljs(f, pvp, t) {
What is the specification to render ClientBehaviorHolder?
Use ClientBehavior#getScript() to get the autogenerated script. It requires a ClientBehaviorContext argument which can be created using ClientBehaviorContext#createClientBehaviorContext(). It's in turn your responsibility to render it into the appropriate HTML attribute, such as onclick.
FacesContext context = FacesContext.getCurrentInstance();
UIComponent inputOrCommandComponent = ...; // Your component.
String event = "click"; // Just the particular HTML DOM event name you need to listen on.
ClientBehaviorContext clientBehaviorContext = ClientBehaviorContext.createClientBehaviorContext(context, component, event, component.getClientId(context), null);
StringBuilder builder = new StringBuilder();
for (ClientBehavior behavior : component.getClientBehaviors().get(event)) { // Collect all <f:ajax> declarations on the given event.
builder.append(behavior.getScript(clientBehaviorContext));
builder.append(';');
}
String script = builder.toString();
// Write it to the desired HTML attribute.
Note that you absolutely don't need to worry about writing JSF implementation specific scripts this way. They will be generated for you.
All with all, ClientBehaviorHolder is just an abstraction of ajax support. It allows developers to nest <f:ajax> in your component. All standard JSF UIInput and UICommand components implement it.

play framework 2.0 - internationalization - how to translate a message

First question: how can I retrieve the translation of a text in a controller?
Second question: how can I retrieve the translation of a text in a template?
The api says that there is a .get method that translates a message:
http://www.playframework.org/documentation/api/2.0/java/play/i18n/Messages.html
However my application does not recognize this method. Opening in eclipse the Message.class shows that there is an .apply method in it, written in Scala and Java!?
object Messages {
/**
* Translates a message.
*
* Uses `java.text.MessageFormat` internally to format the message.
*
* #param key the message key
* #param args the message arguments
* #return the formatted message or a default rendering if the key wasn’t defined
*/
def apply(key: String, args: Any*)(implicit lang: Lang): String = {
Play.maybeApplication.flatMap { app =>
app.plugin[MessagesPlugin].map(_.api.translate(key, args)).getOrElse(throw new Exception("this plugin was not registered or disabled"))
}.getOrElse(noMatch(key, args))
}
Now eclipse tells me that I can invoke this method like this:
> String play.api.i18n.Messages.apply(String arg0, Seq<Object> arg1,
> Lang arg2)
But what should I enter as the "Seq" argument?
--The solution--
The problem was that I imported play.api.i18n.Messages instead of play.i18n.Messages ...
Having defined two message files (messages.de-DE and messages.en-UK) and using the following code everything works fine:
Controller:
import play.i18n.Messages;
import play.api.i18n.Lang;
Lang en = new Lang("en","GB");
play.i18n.Lang en_lang = new play.i18n.Lang(en);
Lang de = new Lang("de", "DE");
play.i18n.Lang de_lang = new play.i18n.Lang(de);
Logger.info(Messages.get("home.title"));
Logger.info(Messages.get(en_lang, "home.title"));
Logger.info(Messages.get(de_lang, "home.title"));
application.conf
application.langs="en-GB,de-DE"
Getting the translation inside the controller:
// in messages file
msg.key=Hello Translation
// in you controller
Messages.get("msg.key");
You can even pass parameters:
// in messages file
msg.key=Hello {0}, here is your translation
//in controller
Messages.get("msg.key", User.firstName);
From the view you can use: Messages("msg.key")
You can even apply HTML formatting (only applicable for views of course):
// in messages file
msg.key=Hello <strong>{0}</strong>, here is your translation
// in controller
Messages.get("msg.key", User.firstName);
//in view
#Html(objectInView)
Please note the following:
Currently it is not possible to define the language explicitly, see bug report: https://play.lighthouseapp.com/projects/82401/tickets/174-20-i18n-add-ability-to-define-implicit-lang-for-java-api
Similar question was asked before:
Access translated i18n messages from Scala templates (Play! Internationalization)
i18n error: controller and templates uses different implicit languages

Resources