PDA

View Full Version : Ext Direct Java based implementation



Pages : [1] 2

pagullo
1 Jul 2009, 9:47 AM
We have finished the first public release of DirectJNgine, an Ext Direct implementation for Java.

You can find the project at http://code.google.com/p/directjngine/.

As far as we know, DirectJNgine is fairly feature complete. For example, it runs all examples provided by ExtJs in examples/direct, as well as our own additional examples and a host of automated tests.

But, of course, we have to wait for feedback from the community to make sure that it fits the community needs, and that it implements the mandatory Ext Direct feature set.


Main features

- Supports all types of request: JSON requests, batched JSON requests, form posts, form posts with file uploads and even polling provider based requests.
- Fully tested: more than 75 fully automated tests as of version 0.7.1 (beta).
- Provides a detailed User's Guide (http://directjngine.googlecode.com/files/DirectJNgine%20User%27s%20Guide.0.7.1.beta.pdf) (more than 20 pages).
- Runs all of ExtJs examples in examples/direct.
- Provides additional examples.
- A WAR is enclosed showing all examples and running all automated tests.


For a complete feature list, go to http://code.google.com/p/directjngine/.


How it works -in 30 seconds

If you are curious about how it works, there is a short excerpt from the User's Guide:

Now, how is everyday life with DirectJNgine?
Let’s assume that you want your Javascript code to call a sayHello Java method, which will receive a person name and return a greeting message. That is as easy as writing the following Java code:



public class Action1 {
@DirectMethod
public String sayHello( String name) {
return “Hello, ” + name + “. Nice to meet you!”;
}
}Basically, you write your Java code without much concern for whether it will be called by some Javascript code living in a remote server or not. The secret? Using the @DirectMethod annotation DirectJNgine... Of course, there are things to configure, best practices to follow, etc. But adding a new method will just feel like this.
For further detail, read the User's Guide (http://directjngine.googlecode.com/files/DirectJNgine%20User%27s%20Guide.0.7.1.beta.pdf), please.


What will be there in version 1.0?

For the 1.0 release we will provide all that's there in the 0.7.1, and then we plan to:

- Add support for custom data conversion from Javascript to JSON to Java and back.
- Enhance the documentation a bit.
- Increment the number of automated tests well beyond one hundred.
- Fix small issues.

We are especially interested in finding all missing pieces there might be with respect to the mandatory feature set.

And, of course, we are open to feedback and criticism, and will consider other features for which there is a strong demand from the community.



Beyond 1.0...

We would love to add better exception reporting...

We might have to optimize logging: we do some heavy duty logging when logging level is set to DEBUG or TRACE, a must when you are dealing with remote communications and data conversion from Javascript to JSON to Java and back.

We would like a "safe client call" mode: just try calling MyAction.myMethod( 1, undefined, 2), and you will probably be in for a surprise.
Or try returning Long.MAX_VALUE from a Java method, and check what number Javascript receives. Avoiding dangerous calls or at least emitting warnings would be nice...

It would be nice to handle individual requests in batched requests in separate threads, now that we have those nice multicore CPUs...

And there is the polymorphism issue, when passing objects from Java to JS and then back to Java...

That said, this is just food for thought, and we having committed yet to post-1.0 features.


Feedback and criticism

We are releasing this library in the hope that it is useful to the programming community.
We understand that this is the first public beta release of the library, which has been tested in a very restricted environment. Unfortunately, that can only guarantee that there is not way for it to be fully feature complete or bug free.

We are committed to making DirectJNgine a useful library. Therefore, it is only natural that we will be happy to receive feedback and criticism.

Last, but not least, we hope you enjoy using DirectJNgine as much as we did developing it.

Regards,

Pedro

aconran
4 Jul 2009, 5:13 AM
Pedro -

This looks great! I will add your implementation to the master list of Ext.Direct Server-side stacks (http://extjs.com/forum/showthread.php?t=67992).

Thanks,

Georgioa
6 Jul 2009, 5:19 AM
This is great !!

I've tested with extsjs examples, and it works fine.

We will use it for our project and be sure you'll get feedback if we find bugs.

Very nice ! =D>

Condor
6 Jul 2009, 5:25 AM
Any chance of adding support for Apache Commons Attributes (http://commons.apache.org/attributes/) to DirectJNgine for people still working on Java 1.4?

pagullo
6 Jul 2009, 11:44 AM
Oops. Yes, those using JDKs older than 1.5 are stuck.
We need to address this issue.

I don't like much adding preprocessing steps to compilation, and I think that will be a must with the Apache Commons Attributes (http://commons.apache.org/attributes/) library -haven't used it though, maybe there are alternatives...

Anyway, DirectJNgine annotations are really simple, and we can do without their parameters 99% of the time. I don't think I will add complex annotations later. No need for a full fledged substitute for 1.5 annotations.

So, what about using a naming convention instead?

- Methods starting with "djn_" will be considered as annotated with @DirectMethod
For "djn_xyz" the method name will be "xyz."

- Those starting with "djnform_" will be considered as a form post method (@DirectPostMethod).
For "djnform_xyz" the method name will be "xyz."

- Those starting with "djnpoll_" will be considered as @DirectPollMethod.
For "djnpoll_xyz", the event name will be "xyz".


This solution is simple, easy to understand and easy to implement. I think this solves the issue.

If it is acceptable to everybody, I will consider it for inclusion in the next public release (0.7.3, due on Wednesday 15).

What do you think?

Regards,

Pedro Agullo

asgillett
6 Jul 2009, 3:39 PM
When I tried the supplied war file, it worked perfectly well with firefox3.5, but failed with javascript errors on IE7.

I thought the user guide was very well written, although still a little incomplete.

I'm looking forward to the next release.


Andrew

Edit: found the problem for IE - too many commas in your javascript!
Remove the commas in DirectStoreDemo.js at lines 36, 42 and 59 and
FormPostDemo.js lines 67 and 80.

pagullo
6 Jul 2009, 10:16 PM
Thanks for the encouraging words.

I will fix the IE issues for the next version, due out tomorrow.

For the final version I plan to add a step to the release procedure for running the automated tests against all major browsers.

Georgioa
8 Jul 2009, 1:46 AM
A little error in doc :

Page 13 :


In this case, we have to pass the form’s el element as the first and only parameter to a server
method annotated with @DirectFormMethod, which is implemented as follow

@DirectPostMethod ?

pagullo
8 Jul 2009, 2:08 AM
Fixed! Thanks.

Georgioa
8 Jul 2009, 5:22 AM
I tried to modify a little FormPostDemo.js and the Java to do something like that :


var remotingProvider = Ext.Direct.addProvider( Ext.app.REMOTING_API);
Djn.RemoteCallSupport.addCallValidation(remotingProvider);

var form = new Ext.form.FormPanel({
// url: Ext.app.PROVIDER_BASE_URL,
api:{
load: FormPostDemo.load, // Something to load, work perfectly
submit: FormPostDemo.submit // here is the problem
},

..... Config / Items / etc......

buttons: [{
text: 'Submit',
handler:function(){
form.getForm().submit();
// here is the problem
}My Java method :


@DirectPostMethod
public Result submit(Map<String, String> formParameters, Map<String, FileItem> fileFields ) throws IOException {

for( String fieldName : formParameters.keySet()) {
System.out.println( fieldName + "</b>='" + formParameters.get(fieldName) + "'<br>");
}
return null;
}


When i do this, RemoteCallSupport throws an exception, i have 3 parameters wheras the method len is 1.

If i delete the verification on remotingProvider, it works.

Is it a bug?

It would be nice to do things like that to have generic formpanels and just configure them.

Regards,
GeorgioA

pagullo
8 Jul 2009, 8:52 AM
I slipped DjnRemoteCallSupport in the example file by accident, as it still needs to be tested for different types of method calls. That's why it worked ok in the example, but as soon as you tried to modify the demo to use the "api" thing it didn't work. Just do not use it by now!

As far as you do not leak "undefineds" in the parameter list or as part of any array at any level in the object structure of your parameters, you'll be on the safe side -most of the time...

BTW, the ExtJs guys changed one of their demos while going from 3.0.0 RC3 to final, and now the "examples/direct/direct-form.js" demo uses the "api" thing, showing how to perform server side field validation.

Since I have updated DirectJNgine to use the final version of ExtJs, and have implemented the demos, you might want to take a look when I release the new version later this evening.

Regards,

Pedro Agullo

P.S.: you will have to change @DirectPostMethod to @DirectFormPostMethod, all other things will remain the same.

pagullo
8 Jul 2009, 9:30 AM
We are releasing DirectJNgine 0.8 (http://code.google.com/p/directjngine/) to accompany the final release of ExtJs 3.0.0.

Since the final version of ExtJs has minor changes with respect to the release candidate, we advise you to upgrade both libraries so that they work well together.

If you are new to DirectJNgine, you might want to take a look at the User's Guide (http://directjngine.googlecode.com/files/DirectJNgine_User_Guide.0.8.pdf).

Here are the new and improved features:

New: support for ExtJs 3.0.0 (final)
The final release of ExtJs 3.0.0 has some changes with respect to the last release candidates, and we have modified djn accordingly.

New: support for old JDKs (prior to JDK 1.5)
Now there is support for JDKs prior to 1.5: it is possible to define direct methods, form post methods and poll methods using a new naming convention, so that annotations are not required.

Therefore,


@DirectMethod
public String sayHello( String name) {
return “Hello, ” + name + “. Nice to meet you!”;
}
can be written as follows


public String djn_sayHello( String name) {
return “Hello, ” + name + “. Nice to meet you!”;
}The method name in the javascript client will be sayHello in *both* cases, to avoid impacting client code.

Check the User’s Guide (http://directjngine.googlecode.com/files/DirectJNgine_User_Guide.0.8.pdf) for further info.

New: "official" support for browsers other than Firefox
The first public beta of DirectJNgine was fully tested against Firefox only.
We have updated our delivery process so that now it includes running all tests and examples against the following browsers:

- IE: version 8.0.6001.18702,
- Firefox: version 3.5.
- Safari: version 4.0 (530.17)
- Chrome: version 2.0.172.33

All of our demos and automated tests run successfully against all of them.

Unfortunately, Opera (version 9.64) does not pass all tests due to problems with upload form posts. Examples with forms including file input fields do not work either. We are investigating the issue.

Improved: tests
Our automated test suite has grown to more than 80 tests.

Improved: fixes
We have fixed several issues with our examples and IE, as well as the User's Guide. Now the example WAR runs as-is against all supported browsers.

Improved: User’s Guide
Added information about how to use djn with JDKs older than 1.5.

Code breaking changes
The @DirectPostMethod annotation has been renamed as @DirectFormPostMethod.

mct
8 Jul 2009, 10:51 PM
Hi,
DirectJNgine is a very good Job. It just works fine.
I also like the User's Guide documentation, it's very clear and neat.
Good continuation.
Thank you.

maxm165
12 Jul 2009, 1:53 PM
Hi!
Very impressing work!
I work for extdirec4j (http://extjs.com/forum/showthread.php?t=67956)project. But DirectJNgine is much better!;)
So i think after occurrence of DirectJNgine our project can be closed. Otherwise it on will similar 'to invent a wheel twice'.:D
Let me post some feature request which have already been implemented in extdirect4j and i think can be usefull for DirectJNgine.

1. To provide to user an access to GsonBuilder to register custom user TypeAdapter(may be it would be better to have 'custom' and 'system' GsonBuilders to prevent collision). I guess it is very important feature!
2. Why not to have possibility to set action class programmaticly(for example, the class has been created at runtime) and also to set an object of action class(created with argumented constructor despite what it is not provided in ExtDirect spec).

Please let me know what are you thinking about this ideas? If you do not have enough time to implement the future features i with the great pleasure would take a part in development.
Best Regards.

-Maxim Egorov-

pagullo
13 Jul 2009, 10:29 PM
Hi, Maxim!
Thanks for your kind words!

Customizing Gson, including custom serialization/deserialization, etc., was in the version 1.0 roadmap, and is already implemented in the version under development, which will see the light in a few days.

With respect to programmatic method registration, I am considering it.

If it is implemented, a possibility is to read a list of additional classes to scan from a properties file, say 'myApi.djn.api.properties' -easy to implement.
If you need to generate a class at runtime, you should do so at application startup time,before the servlet is initialized, adding the full class name to the properties file.

How do you think about that?

Regards,

Pedro Agullo

maxm165
13 Jul 2009, 11:06 PM
Hi, Pedro!
Thank you for reply!
I think it is great.
But i think injection of initialized object of action class is a good idea too (it will allow to create actions by constructor with an arguments and would make DirectJNgine more flexible).
By the way may i ask you offtop question how many the person in your team? Do you develop project at leisure or for work?

Thanks.

Animal
14 Jul 2009, 2:37 AM
You need to include an ANT script to build the war.

I'm getting



SEVERE: Error deploying web application archive djn_test.war
java.lang.UnsupportedClassVersionError: Bad version number in .class file


on deployment, so I need to rebuild the war file using my installed JDK.

pagullo
14 Jul 2009, 10:41 AM
Hi!

animal: Oops. Yes, the pre-cooked WAR is compiled against JDK 1.6, need to run against it.

Will fix that long-term by adding the build.xml file -current one is too dependent on my personal configuration, can't distribute as-is.

Thanks.

...

maxim: can you provide a pair of concrete use cases about the injection thing? If it is to be implemented, I want to be *absolutely* sure about the programmatic API.

I don't like much the prospect of regenerating the api files every now and then, the fact that the API is full know at servlet initialization time means I can generate the JS files *once and for all* (and spend extra time minifying them, etc.). So, adding more actions/methods via some callback at servlet initialization time is ok.

Of course, if the API changes, I rely on restarting the app, and then files are regenerated if the API has changed. Well, that's exactly what I do when adding/modifying Java classes, and it is enough 99% of the time.

Now, will you do with just adding actions/classes at initialization time? If that's not the case, can you show me a pair of common scenarios for which you think it is a must to add methods after servlet initialization?

With respect to your other questions: I am the only programmer behind DirectJNgine, and I run it as a leisure project, even though I am fully committed to support it.

That said, I get to spend a percentage of my work-time doing "as-I-want" research, and I'm very interested in what ExtJs has to offer, so I'm devoting additional time to it. It might happen that we move to ExtJs at work, but that depends on many other issues, DJN being just a little piece of the puzzle.

...

Regards,

Pedro Agullo

Animal
14 Jul 2009, 12:48 PM
OK, I'll test against a 6.0 JDK. We just standardize on 5.0 at work over all our platforms, so that's what I run by default.

maxm165
15 Jul 2009, 2:01 AM
I just have very unusual and exotic use case in real work. Try to explain..
We have a system which allows business users to create/modify, compile/recompile and finally run same custom executable java class on the fly without rebuilding/redeploying whole application. I know that doing extdirect interceptor by this way is a bad practice, but can't refuse convenience of creation of direct actions on the fly at least in debug phase.:)
Therefore i have implemented registering of initialized object as a remote direct action.
But you are really absolutely right it is a application designing problem, but not rpc engine.

Thank you for discussion. Will study on your experience.
Wish you the best in work with ExtJs.

Maxim.

Animal
15 Jul 2009, 3:28 AM
Pedro, one thing that I am used to from DWR, is not including a hardcoded (Even if it's generated) file to specify the API, but includnig a request to a servlet to generate it on the fly..

Instead of having the servlet generate a named file the name of which is a mandatory config, how about we make the API file name optional, and have it only create it if the ApiConfiguration.Parameters.API_FILE is specified in the servletConfig?

Then just serve the API directly, generating it as needed:

Changes to DirectJNgineServlet


@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {

// Allow client to include <script type="text/javascript" src="/djn_test/djn/directprovider/?getApi"></script>
if (request.getParameter("getApi") != null) {
registry.writeApiScript(this.globalConfiguration, response.getWriter());
return;
}

RequestType type = getFromRequestContentType(request);
response.setContentType("text/html"); // MUST be "text/html" for uploads to work!

switch( type ) {
case FORM_SIMPLE_POST:
this.processor.processSimpleFormPostRequest( request.getReader(), response.getWriter() );
break;
case FORM_UPLOAD_POST:
processUploadFormPost(request, response);
break;
case JSON:
this.processor.processJsonRequest( request.getReader(), response.getWriter() );
break;
case POLL:
this.processor.processPollRequest( request.getReader(), response.getWriter(), request.getPathInfo() );
break;
}
}


Addition to Registry


public void writeApiScript(GlobalConfiguration globalConfiguration, Writer out) throws IOException {
assert globalConfiguration != null;

StringBuilder result = new StringBuilder();
for( RegisteredApi api : getApis() ) {
ApiCodeGenerator generator = new ApiCodeGenerator( globalConfiguration, api );
generator.appendCode(result);
}
out.append(result);
}


Of course until we get a build script we can't really experiment with the code...

Animal
15 Jul 2009, 3:29 AM
Of course you'd probably implement a new RequestType enum member.

pagullo
15 Jul 2009, 2:28 PM
maxim:
Agreed!

That said, I think you might get what you want by subclassing from DirectJNgineServlet. Next version will provide some refactorings that might make this easier (some protected methods to override...).

...

animal:
Just so that I get a better understanding... Is there some issue I'm missing about having a generated file vs. generating the content on the fly? Can you elaborate on why you would like to have the request content generated on the fly?

There is a nice pro about using a generated file: if it is not modified, the client will know and there will be no need to transfer the file content. The client pays for posing the "do I need to read the file again?" question, but does not pay for the data transfer unless the file has been modified. And the web server will do this without DirectJNgine having to do anything.

BTW: we generate the file only when it is strictly needed, not every time we initialize the servlet, much less every time the file is requested. Maybe you were worried about the files being rewritten all too often?

Those are the reasons why I had chosen the "generated file" approach.

Now, If the mandatory file name parameter bugs users, we might make it optional by providing a default file name, such as "DirectJNgineApi.js". I think this is pretty minor, though.

Have the feeling that maybe I am missing something, though...

...

There are several api-related enhancements already finished in current development version that might be relevant to the discussion at hand:

- Api files will be minified: for an xxx.js api file you will get xxx-debug.js (well formatted and very readable, includes comments that describe the Java parameter/return types), xx-min.js (no comments, minified) and xxx.js. If in debug mode, xxx.js will be equivalent to xxx-debug.js, else it will be equivalent to xxx-min.js.

BTW: I would not like to have to minify files on the fly, it is relatively slow because we are using YUI Compressor, probably the best and slowest one (near 300 ms to minify the test api file...).

- Api consolidation: several apis can be consolidated in just one api file. Why?

1) You get get logical encapsulation: for example, in the test/demo app we have separated demo and test apis, as I feel they are different things.

2) You get finer configuration : all methods belonging to an api belong to just one provider. You can configure different providers differently.

3) The client receives just one file, minimizing number of client-server transfers.

BTW: I hope I had made it more clear that "api"="provider" in the User's Guide.

pagullo
16 Jul 2009, 8:14 AM
DirectJNgine 1.0 RC1 is out, with several new features and improvements. You can donwload it here (http://code.google.com/p/directjngine/downloads/list).

From now on we plan to fix issues, perform some cleanup and enhance the User’s Guide (http://directjngine.googlecode.com/files/DirectJNgine_User_Guide.1.0.RC1.pdf) a bit so that we can release DirectJNgine 1.0 final as soon as possible, without adding any more functionality or changing the API.

Of course, that's the plan: we are open to adding new features if they turn out to be really important, and revamp existing ones if we must. While we intend to release 1.0 final as soon as possible, it is much more important that the final release is robust, has a solid api, and is feature complete.

We look forward to receive feedback from the community in order to make 1.0 final as good as possible!

...

Here is a list of new and improved things in this release...

New: support for custom Gson configuration and serialization/deserialization
Gson is very powerful, but there will be cases when you might need to change its configuration or customize how to handle certain Java types.
Need to pass Java Calendars around? You can do it now!

New: multithreaded batched request handling
DirectJNgine supports multithreaded individual request handling for batched requests, making it possible to get much better performance in certain scenarios.

New: minification and comment removal from generated API files
Minimize size of API files, optimizing data transfer.
As an example, we have found that our test api file is compressed from 14.689 to 7.103 bytes, a 52% compression.

New: mutiple API consolidation in a single file
Now you can group several Ext Direct APIs in a single file, minimizing the number of requests a client needs to retrieve a page.

New: build.xml for ant users
We provide support for compilation and demo war generation/deployment with ant, to make life easier to those interested in playing with DirectJNgine.

New: performance data logging
We are generating logs for performance data: how much time is spent in DirectJNgine, how much in your Java methods, the time it takes to start DirectJNgine, minify the api files, serve individual requests in a batched request, etc.

Improved: better and faster logging
We have enhanced logging to get better diagnostics and know what log messages are part of a given request.
We have improved performance removed all overhead from logs, so that you only pay for debug logging if you have it activated: there is near zero overhead if you have no debug logging.

Improved: User’s Guide
The User’s Guide (http://directjngine.googlecode.com/files/DirectJNgine_User_Guide.1.0.RC1.pdf) has been augmented with additional chapters explaining the new features, and has grown to 30 pages in length.

Improved: general performance improvements
We think DirectJNgine is very fast.
As an example, during repeated test execution in a Core Duo running at 3.33 GHz we have found that 90% of the individual requests consumed less than 5 ms in DirectJNgine itself.

Besides, the new api generation functionality and multithreaded execution of batched requests make it even faster.

Animal
17 Jul 2009, 6:24 AM
I feel sure I've replied today...

Anyway. Thanks for the update. Especially the ANT script.

Perhaps the API file could have a default name based on the name of the API.

So my config could be



<init-param>
<param-name>apis</param-name>
<param-value>aspicio</param-value>
</init-param>

<init-param>
<param-name>aspicio.apiFile</param-name>
<param-value>aspicio-api.js</param-value>
</init-param>

<init-param>
<param-name>aspicio.namespace</param-name>
<param-value>com.aspicio</param-value>
</init-param>

<init-param>
<param-name>aspicio.classes</param-name>
<param-value>com.fcl.net.MailUtils</param-value>
</init-param>


And it would still create "aspicio-api.js".

Also, that creates the api file like



Ext.namespace( 'com.aspicio');

com.aspicio.PROVIDER_BASE_URL=window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/')[1]) + '/' + 'djn/directprovider';

com.aspicio.POLLING_URLS = {
}

com.aspicio.REMOTING_API = {
url: com.aspicio.PROVIDER_BASE_URL,
type: 'remoting',
actions: {
MailUtils: [
{
name: 'sendMail'/*(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) => java.lang.String */,
len: 5,
formHandler: false
}
]
}
}


The semicolons are missing.

Also, it needs to tell the Provider what namespace it is in! The provider cannot "detect" that it is in com.aspicio, so it should be



Ext.namespace( 'com.aspicio');

com.aspicio.PROVIDER_BASE_URL=window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/')[1]) + '/' + 'djn/directprovider';

com.aspicio.POLLING_URLS = {
};

com.aspicio.REMOTING_API = {
namespace: com.aspicio,
url: com.aspicio.PROVIDER_BASE_URL,
type: 'remoting',
actions: {
MailUtils: [
{
name: 'sendMail'/*(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) => java.lang.String */,
len: 5,
formHandler: false
}
]
}
};


But why also is that Provider not instantiated? Why is the file not



Ext.namespace( 'com.aspicio');

com.aspicio.PROVIDER_BASE_URL=window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/')[1]) + '/' + 'djn/directprovider';

com.aspicio.POLLING_URLS = {
};

com.aspicio.REMOTING_API = {
namespace: com.aspicio,
url: com.aspicio.PROVIDER_BASE_URL,
type: 'remoting',
actions: {
MailUtils: [
{
name: 'sendMail'/*(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) => java.lang.String */,
len: 5,
formHandler: false
}
]
}
};

Ext.Direct.addProvider(com.aspicio.REMOTING_API);

pagullo
17 Jul 2009, 10:59 AM
- With respect to using a default api file name, like your idea.

Will be there in DJN 1.0 final, probably using the naming suggestion you provide.

Thanks!

- The 'namespace' configuration parameter
There is a really *little* but *very nasty* issue, which is the reason why I didn't add it as you suggest from day one.

The direct examples in ExtJs do not use namespaces for the apis, and I really want people to be able to run them against DirectJNgine without having to change more than one line of code per example file.

If I add the namespace configuration parameter to the demo api as you suggest, it will take as value Ext.App.
Then the calls to the methods in ExtJs direct examples will have to be modified to something like


Ext.App.TestAction.doEcho(...)instead of the existing


TestAction.doEcho(...)Asking people to modify one line to port from PHP backend to Java backed is ok, telling them to "look for all occurrences of all methods (you check what 'all' is)" is not.

They will think "why does that DirectJNgine thing force me to do all those changes? Must no be that good".
And they will be right, software is as software does...

On the other hand, I need the apiNamespace not to be empty: I don't want two global 'REMOTING_API' or 'PROVIDER_BASE_URL' occurrences if I generate two apis.
I want them namespaced. That's what apiNamespace was for in the beginning.

That's why namespace is not set to apiNamespace: the obvious thing to do is not good enough. I know, very picky!

But I want to use the 'namespace' config param, it was already in the "to polish" list for 1.0 final...

Maybe I should provide two parameters, actionNamespace and apiNamespace? But, don't like it, really.

But, why not to use the api name much like you suggested for the default file api name?

If apiNamespace is blank, use the api name as the namespace for REMOTING_API, etc., and ignore the namespace config param.
Else, use apiNamespace both for the namespace config param and the REMOTING_API namespace!

This solves the problem with the ExtJs direct examples, I just remove the apiNamespace parameter or leave it blank for them.

Hmm. Looks better.

No matter how the thing is solved, namespace must be supported.
It will be there in 1.0 final, sure "as the day follows the night" ;).

- Missing ";": though everything works well without them (am I right?), it is a good coding practice.

When I have some time will run all JS files against JSLint, and will clean all JS code.
I'm sure there are more of these, 95% of my attention is focused in the Java side of the equation...

- Registering the provider in the generated api file
Alpha versions did that. Why did I remove it?
In one of my files, I have this, to test for non-batched requests:


DjnTestApi.REMOTING_API.enableBuffer = 0;
var remotingProvider = Ext.Direct.addProvider( DjnTestApi.REMOTING_API);
If we had called addProvider in the api file, this would be the second registration for the api.
Hmm. Does not feel right.

Think will not do into 1.0 final.

...

Thanks for the feedback. I know it takes time!

BTW: let me kow how it goes with the enclosed build.xml.
Not completely happy with it, so if you can improve it, I will be happy to add your improvements.

mct
23 Jul 2009, 4:00 AM
Hi, I deployed one application that retrieves data from PostgreSQL on Tomcat 6.0.20 with java-6-sun as the JVM, it works very good.
But when I change the Tomcat's JVM to java-6-openjdk, the application stops retrieving data with errors. So please try to change the JVM on your test machine and see if you have the same problem.
The OpenJDK is very important for me because we are working on Ubuntu, and on Ubuntu Server the OpenJDK is the default one.
Excuse me for my English.



Best Regards

pagullo
23 Jul 2009, 5:29 AM
Hi.

Can you be more specific?

- When does it stop working? At startup? Trying to satisfy some kind of request? Inside your own Java code, in DirectJNgine code, or somewhere else? Simplify your app. to the bare mimimum to isolate the problem as much as possible.
- What messages do appear? Stack trace?
- Turn logging to ALL for "com.softwarementors" in log4j.properties, and take a look at it.
- And, are you sure this is DirectJNgine related?

Regards,

Pedro.

mct
23 Jul 2009, 6:02 AM
Hi,
Here is the message under eclipse console:



23 juil. 2009 14:51:30 org.apache.catalina.core.ApplicationContext log
GRAVE: StandardWrapper.Throwable
java.lang.RuntimeException
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.printSourceNumber(JavaScriptCompressor.java:299)
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.parse(JavaScriptCompressor.java:336)
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.<init>(JavaScriptCompressor.java:533)
at com.softwarementors.extjs.djn.config.Minifier.minify(Minifier.java:42)
at com.softwarementors.extjs.djn.config.Registry.saveCode(Registry.java:366)
at com.softwarementors.extjs.djn.config.Registry.updateJavascriptApiFiles(Registry.java:330)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.createDirectJNgineRouter(DirectJNgineServlet.java:119)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.init(DirectJNgineServlet.java:99)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:809)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:129)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Thread.java:636)
23 juil. 2009 14:51:30 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Exception lors de l'allocation pour la servlet DjnServlet
java.lang.RuntimeException
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.printSourceNumber(JavaScriptCompressor.java:299)
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.parse(JavaScriptCompressor.java:336)
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.<init>(JavaScriptCompressor.java:533)
at com.softwarementors.extjs.djn.config.Minifier.minify(Minifier.java:42)
at com.softwarementors.extjs.djn.config.Registry.saveCode(Registry.java:366)
at com.softwarementors.extjs.djn.config.Registry.updateJavascriptApiFiles(Registry.java:330)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.createDirectJNgineRouter(DirectJNgineServlet.java:119)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.init(DirectJNgineServlet.java:99)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:809)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:129)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Thread.java:636)

and here the log4j.properties :


##############################################################
# Loggers: per-package configuration
##############################################################

log4j.logger.com.softwarementors.extjs.djn=ALL
log4j.logger.com.softwarementors.extjs.djn.Timer=ALL


Regards.

pagullo
23 Jul 2009, 11:03 AM
Not a DirectJNgine related problem.

Just a known bug for some OpenJDK version + YUI Compressor library in Ubuntu...Take a look at https://bugs.launchpad.net/ubuntu/+source/openjdk-6/+bug/287035, please.

They mention some kind of fix. Let us know how it all ends up, please.

If you can't make it work or can't find a workaround, I will consider adding the possibility to bypass api files minification...

Regards,

Pedro

mediacept
23 Jul 2009, 1:17 PM
Hi,
I found the solution in this forum:
https://bugs.launchpad.net/ubuntu/+source/openjdk-6/+bug/255149

There is a symlink named rhino.jar in /usr/lib/jvm/java-6-openjdk/jre/lib.

I removed it and now my application works without problems.
You sayed:


I will consider adding the possibility to bypass api files minification...
It will be a good idea for the next release (let's say DirectJNgine 2.0, for example), because it seems that this bug with OpenJDK will not be solved by Ubuntu for they next release (Ubuntu 9.10).


By the way, can you tell me please something about the release date of the final DirectJNgine 1.0.

Thank you.

Best Regards,

Ramzi Youssef
MEDIACEPT Technology

J@y
26 Jul 2009, 8:48 PM
Just a quick question: Which files do we need for the installation of Djn in order to make it works?

I mean the minimal files for basic functionalities of Djn, thanks

I'm not very clear to the installation in the user guide, could you please explain it in details? thanks

J@y
26 Jul 2009, 10:05 PM
Ok, after re-reading the user guide several times and try out the demo app. I've figured out something, please correct me if I made any mistakes.

The folders and files we need under our "webContent" folder:
1.) djn/*
2.) ejn/*
3.) test/*
4.) WEB-INF/lib/*.jar

The files we have to configure for our app:
1.) WEB-INF/web.xml

The files which will be auto generated:
1.) Api.js
2.) Api-debug.js
3.) Api-min.js

Do I miss anything else?

pagullo
27 Jul 2009, 2:18 AM
From the User's Guide in the DirectjNgine version under development:


In order to use DirectJNgine in a new application, you will need to add the following JARs to your webapp WEB-INF/lib directory:

• DirectJNgine itself: the file is deliverables/directjngine.xxx.jar, where xxx is the version number, such as 1.0.

• Third party libraries used by DirectJNgine:
- All JARs in the lib directory. Please, *ignore* its subdirectories, we are referring to files in the root directory only.
- All JARs in the lib/runtimeonly directory.
- Important: do NOT add the JARs in lib/compiletimeonly.

...

Finally, you will need to provide the ExtJs files: due to licensing issues you need to download them separately, and then install them in your web app.

The enclosed demo app might use some other files, but they are not needed in order to use DirectJNgine, and they are not part of it.

Compilation only JARs
In order to compile, you might need the libraries in lib/compiletimeonly or not, depending on how your environment is set up.

This directory contains JAR files the web server will already provide, so you must not add them to your app WEB-INF/lib directory....

While this is from the User's Guide for the next DirectJNgine release, it applies to 1.0 RC1.

As for DJN 1.0 RC1, there are NO javascript files to redistribute. The js files you see in the demo app are used and supported *only* in the demo application.

That said, the final release will add some utility javascript files, and the User's Guide will explain when and how to use them. But they will be utilities, not mandatory.

...

With respect to the ApiXXX.js files you mention, they are regenerated as needed, you need not worry about distributing them.

...

I hope this is clear enough!

Regards,

Pedro.

J@y
27 Jul 2009, 5:05 AM
Thanks Pagullo.

Since we are going to use Djn in our existing production developement, do you recommand us to do so?

Currently we are using the DWR+DWRProxy of Extjs, everything works fine except the integration part to the extjs framework.

What I concerning about is, the difference of performance and reliability between DWR and Djn. Would you please give me some suggestions/advices on this?

Again, highly appreciated for your help

pagullo
27 Jul 2009, 8:04 AM
Hi.

First of all, since I am the person behind DirectJNgine, you should take my words with a grain of salt, to say the least...

...

I think the pieces in the puzzle are as follows:

Option 1
ExtJs + DWR + DwrProxy as "glue"

Option 2
ExtJs + Direct (part of ExtJs, but an additional/new piece) + DirectJNgine.

So, maybe the things to consider/compare are:

a) Direct vs. DWR.

As somebody else said in some other thread about, DWR is battle tested and proven, a *big* plus, whereas Direct is not proven yet.

On the other hand, you should probably expect Direct to be better integrated with ExtJs, as it is part of the product.
This means you will have focused support: things such as being able to use a Direct function to load a Store data,conventions to return field validation errors to forms from a Direct method, etc.

With DWR, you will probably find yourself missing these little pieces of "glue" code time and again, and you will probably have to write them on your own. But you should check the ExtJs forums for this kind of glue.

I hope that Direct will pass the test of time, as ExtJs has done -a good indicator. In fact, since I implemented the DirectJNgine Java router, it is clear I have some faith in it :-)

And I don't think Direct will vanish, from my point of view it was a missing piece in ExtJs, communication with the backend is a friction point.

But, again, we have to see how things evolve.



b) DwrProxy vs. DirectJNgine
On a first look, these are probably the candidates to be the "weak link" in the chain...

I can't comment on DwrProxy, as I haven't used it. I don't know its scope (does it cover the same ground?), how it is used or any other detail.

As with Direct, DirectJNgine is not battle tested yet, and you have to decide whether you trust it based on external indicators due to the lack of a track record: things such as existence of automated tests, quantity and quality of documentation and demos, opinions in forums, etc.

Of course, I've done my best to make DirectJNgine robust and reliable, and have implemented it as if it were one of the commercial projects I implement/manage.

That's why I emphasized so much automated testing (I developed the testing infrastructure as the first step), demos and documentation: they force you to focus.
I think high quality can't be obtained without focus -but you certainly can get low quality even if you think you are focused.

...

Just my thoughts...

As you can see, I am optimistic both about Direct and DirectJNgine :-)

...

I hope other people comment on this. I know of at least one person that has used DWR + DwrProxy and is giving a try to Direct + DirectJNgine and is very active in these forums.

And maybe the person behind DwrProxy can provide more info on DwrProxy itself and his experiences with DWR.

Regards,

Pedro.

J@y
27 Jul 2009, 8:21 PM
Thanks again Pedro,

After setting up the Djn environment to my new eclipse project, I got the following errors during the server start.
The error messages from the tomcat console:


SEVERE: StandardWrapper.Throwable
com.softwarementors.extjs.djn.servlet.ServletConfigurationException: Unable to find class 'com.labci.ckwui.djn.demo.ChartCbStore'
at com.softwarementors.extjs.djn.servlet.ServletConfigurationException.forClassNotFound(Unknown Source)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.getClasses(Unknown Source)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.createApiConfiguration(Unknown Source)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.createApiConfigurations(Unknown Source)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.createDirectJNgineRouter(Unknown Source)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.init(Unknown Source)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1161)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:981)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4058)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4364)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
at org.apache.catalina.core.StandardService.start(StandardService.java:516)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
at org.apache.catalina.startup.Catalina.start(Catalina.java:578)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
Caused by: java.lang.ClassNotFoundException: com.labci.ckwui.djn.demo.ChartCbStore
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1360)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1206)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
... 22 more
Here is my web.xml configs for Djn:


<!-- DirectJNgine servlet -->
<servlet>
<servlet-name>DjnServlet</servlet-name>
<servlet-class>
com.softwarementors.extjs.djn.servlet.DirectJNgineServlet
</servlet-class>
<init-param>
<param-name>providersUrl</param-name>
<param-value>djn/directprovider</param-value>
</init-param>
<load-on-startup>1</load-on-startup>

<init-param>
<param-name>apis</param-name>
<param-value>
test,
demo
</param-value>
</init-param>
<init-param>
<param-name>demo.apiFile</param-name>
<param-value>js/portal/Api.js</param-value>
</init-param>
<init-param>
<param-name>demo.namespace</param-name>
<param-value>Ext.app</param-value>
</init-param>
<init-param>
<param-name>demo.classes</param-name>
<param-value>
com.labci.ckwui.djn.demo.ChartCbStore
</param-value>
</init-param>

<init-param>
<param-name>test.apiFile</param-name>
<param-value>js/portal/DjnDemo.js</param-value>
</init-param>
<init-param>
<param-name>test.namespace</param-name>
<param-value>DjnTestApi</param-value>
</init-param>
</servlet>

<servlet-mapping>
<servlet-name>DjnServlet</servlet-name>
<url-pattern>/djn/directprovider/*</url-pattern>
</servlet-mapping>
And of cause my java class is placed under the src of eclipse project:\src\com\labci\ckwui\djn\demo.

The JARs in my lib:


commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
directjngine.1.0.RC1.jar
gson-1.3.jar
jargs-1.0.jar
log4j-1.2.15.jar
rhino-1.6R7.jar
yuicompressor-2.4.2.jar
Since this issue came from server side, I don't post my client side javascript code at this moment.

J@y
27 Jul 2009, 8:56 PM
Finally I figured out that the default build path of eclipse is "project/build/classes", it seems that Djn does not refer to this build path.

After I copied the complied classes to the "webContent/WEB-INF/classes", everything works fines.

So the conclusion is, Djn is looking for the .war environment, not the eclipse's dev. environment.

Please correct me if I made mistakes of that.
Thanks:)

pagullo
27 Jul 2009, 10:22 PM
Djn assumes nothing about where the classes are: if the JRE can find them, Djn can find them. Of course, Djn uses the environment in which it is running, the web app.

...

You can get Eclipse to put your compiled classes in your "webContent/WEB-INF/classes" directory: menu "Project|Options", choose "Java Build path", then go to "Source" tab, and set "Default output folder" to point to the directory.

This is all related to how Eclipse and a web app work. You should probably look for additional info on configuring and debugging web app projects in Eclipse forums.

J@y
27 Jul 2009, 11:38 PM
Djn assumes nothing about where the classes are: if the JRE can find them, Djn can find them. Of course, Djn uses the environment in which it is running, the web app.

...

You can get Eclipse to put your compiled classes in your "webContent/WEB-INF/classes" directory: menu "Project|Options", choose "Java Build path", then go to "Source" tab, and set "Default output folder" to point to the directory.

This is all related to how Eclipse and a web app work. You should probably look for additional info on configuring and debugging web app projects in Eclipse forums.

yea I know these things as well, I just notice that Djn is working for running environment only.

thanks anyway, it works very well and seems to be a good replacement of DWR. (ofcoz I still have to test its performance in UAT)

dweller
28 Jul 2009, 1:33 AM
hi,my english is poor.

I met a question.If I return a chinese in server-side class,there be ?? in the client-side page.

what can I do for it?

thanks

J@y
28 Jul 2009, 3:22 AM
hi,my english is poor.

I met a question.If I return a chinese in server-side class,there be ?? in the client-side page.

what can I do for it?

thanks

what are the encoding type of your DB fields? unicode or..?
Of cause your page should also be set into the utf8 encoding.

I haven't tried it on chinese/other languages with Djn, but extjs supports unicode characters display.

dweller
28 Jul 2009, 5:26 PM
I just test TestAction.doEcho methhod.don't use DB,client-page also use utf-8 encode.

Input "世界" in the client page,TestAction.doEcho( String data ) method will print the same.
But In client page will be ??.

whether djn's servelet need to config encode in somewhere?

dweller
28 Jul 2009, 7:01 PM
It seems djn not support utf8.

as I deploy the djn_test war to tomcat6,test TestAction.doEcho method.In server side console:
DEBUG: com.softwarementors.extjs.djn.router.JsonRequestProcessor - "Response dat
a (JSON)=>{"result":"世界","tid":4,"action":"TestAction","method":"doEcho","type
":
but in the direct.html page, there will ??.I try utf-8,gbk,iso8859-1,will the same.

test doEcho in ext.direct package(http://extjs.com/deploy/dev/examples/direct/direct.php),it's ok.

There need to config djn or tomcat server?

J@y
28 Jul 2009, 9:50 PM
It seems djn not support utf8.

as I deploy the djn_test war to tomcat6,test TestAction.doEcho method.In server side console:
DEBUG: com.softwarementors.extjs.djn.router.JsonRequestProcessor - "Response dat
a (JSON)=>{"result":"世界","tid":4,"action":"TestAction","method":"doEcho","type
":
but in the direct.html page, there will ??.I try utf-8,gbk,iso8859-1,will the same.

test doEcho in ext.direct package(http://extjs.com/deploy/dev/examples/direct/direct.php),it's ok.

There need to config djn or tomcat server?

Yes...I got the same problem.

If I type the chinese directly into the .js file (the file saved in utf-8 format), it can be displayed correctly.

If I call the java method(the chinese characters is in utf-8 representation) directly and print the chinese character in the console, it also display the correctly things.

So I think this issue happens during the data coversion from server side to client.
Anyone have solutions?

J@y
28 Jul 2009, 11:48 PM
if I encode the chinese text into html format, it can be displayed correctly.

But I think this is not the proper way to handle the non-english characters.......

pagullo
29 Jul 2009, 12:23 AM
I think it is very likely due to the fact that we use the default encoding provided by the webapp server for the response writer, not forcing it to "UTF-8".

I can' test this right now, but if you are in a hurry, you can check the hypothesis on your own: just add the following line to DirectJNgineServlet.java


response.setCharacterEncoding(EncodingUtils.UTF8);Put it below this line:


response.setContentType("text/html"); // MUST be "text/html" for uploads to work!Recompile and regenerate deliverables with the build_deliverables ant task, use the regenerated DirectJNgine jar, and see what happens.

Let me know whether it works.

Regards,

Pedro Agulló

J@y
29 Jul 2009, 6:44 AM
I think it is very likely due to the fact that we use the default encoding provided by the webapp server for the response writer, not forcing it to "UTF-8".

I can' test this right now, but if you are in a hurry, you can check the hypothesis on your own: just add the following line to DirectJNgineServlet.java


response.setCharacterEncoding(EncodingUtils.UTF8);Put it below this line:


response.setContentType("text/html"); // MUST be "text/html" for uploads to work!Recompile and regenerate deliverables with the build_deliverables ant task, use the regenerated DirectJNgine jar, and see what happens.

Let me know whether it works.

Regards,

Pedro Agulló
I'm quite hurry to fix this problem within this week, but I'm out of town now, so I can't test it myself. I'll ask our dev team to try it.

But as mentioned above, we've tested the non-english char in ExtJS example which provided in the demo page, it can correctly echo the text. (tho they are using PHP)

dweller
29 Jul 2009, 5:07 PM
I'm quite hurry to fix this problem within this week, but I'm out of town now, so I can't test it myself. I'll ask our dev team to try it.

But as mentioned above, we've tested the non-english char in ExtJS example which provided in the demo page, it can correctly echo the text. (tho they are using PHP)

Hi,I've tested the non-english char as you mentioned below.It's ok.
just add:
response.setCharacterEncoding("UTF-8");

And I found another question:If you send non-english char to server by IE6,there will be ?? in server side,of course,client page will be ??.

In fact,it due to ajax post in IE6,in firefox,it's ok.My solution is adding:
request.setCharacterEncoding("UTF-8");

then,post non-english char in IE6,firefox,all is ok.

dweller
29 Jul 2009, 5:17 PM
Hi,

Another question bore me.

How to receive parameters in directStore.

I found a method is ok.

client side code:

var experienceStore = new Ext.data.DirectStore( {
paramsAsHash:false,
paramOrder:'start|limit',
root:'items',
totalProperty : 'rowCount',
directFn: DirectStoreDemo.loadExperienceData,
idProperty:'id',
...
});

experienceStore.load({params:{start:0,limit:10}});

server side code:
public DirectStoreResult loadExperienceData(int start,int limit) {
...
}

then, server side can receive parameters.But there is a problem:can't receive dynamic parameters.

I try this,
client side code:
var experienceStore = new Ext.data.DirectStore( {
paramsAsHash:true,
root:'items',
totalProperty : 'rowCount',
directFn: DirectStoreDemo.loadExperienceData,
idProperty:'id',
baseParams : {
start : 1,
limit : 10 ,
sort : "id",
dir : "ASC"
}
...
});

server side code:
public DirectStoreResult loadExperienceData(JsonArray arguments) {
...
}

but server can't receive any parameter,can anyone help me?

thanks.

pagullo
30 Jul 2009, 1:01 AM
The paramsAsHash: true option is not supported, because I felt it will force us to receive values of unknown types, and I was concerned we might end up writing Java code that receives Object parameters all around (unknow type=> need to use Object as parameter type=> we loose Java's type safety) .

Type safety is one of the reasons for using Java at the server side, else why not using a more dynamic server side language?

Therefore, I'm trying to do writing that kind of code difficult -but not impossible.

That said, can you please provide a pair of concrete use cases in which paramsAsHash:true is needed? Will be glad to re-check my assumptions.

And, can you write here your client side call to 'load'?

I feel it is possible to get a great degree of flexibility without having to use the paramsAsHash: true thing.

Regards,

Pedro

mct
30 Jul 2009, 2:17 AM
Hi Pedro,
As we already started using DirectJNgine in our project (an open source ERP), and as you propounded the July, 22 for the final 1.0 release, can you tell us please something about the release date of the final DirectJNgine 1.0.
Never mind the date, just to know for planing.
Thank you very much.

pagullo
30 Jul 2009, 7:33 AM
We are releasing DirectJNgine 1.0 final today!

Though we had planned to release it in July 22, we decided to add some features that were planned for 1.1 to 1.0, moving a bit the release date: client-side parameter checking and direct JSON handling.

We hope they will be worth the one week delay!

To get DirectJNgine, go to http://code.google.com/p/directjngine/

New: added support for handling JSON directly

From the User's Guide (http://directjngine.googlecode.com/files/DirectJNgine_User_Guide.1.0.pdf):


We have made every effort to handle serialization from JSON to Java, so that you can write methods that receive good old Java data types. However, there can be cases when you might need to access the JSON data directly for maximum flexibility...Now, you can do that by making a method annotated with @DirectMethod receive as its only parameter a JsonArray parameter, and DirectJNgine will pass your method the Json data, without making any attempt to decode it.


New: client-side parameter checking (debug only)

We provide many client-side parameter checks. This is optional, and intended to be used in debug mode only.

Take a look at the User's Guide chapter on parameter checking for further info.

Improved: the User's Guide has grown to more than 40 pages.

We have added several new chapters:

- 4. Configuring a new project to use DirectJNgine.
- 9. Servlet configuration parameters.
- 11. Handling JSON data directly.
- 12. Checking client-side calls.

The chapter dedicated to form handling has been rewritten and enhanced to use the form 'api' configuration parameter.

New: additional servlet initialization parameters
- actionsNamespace: This allows us to provide a namespace for Direct actions.
- minify: this allows us to disable api file minification.

Take a look at the User's Guide for an explanation

Improved: fixes and minor enhancements
- Addressed issue with internationalization.
- Improved build.xml

...

Code breaking changes
The 'namespace' servlet intialization parameter has been renamed to 'apiNamespace'. In DirectJNgine 1.0 we have two "namespaces" now, one for apis and another one for actions, and we felt 'namespace' was misleading.

For further info, take a look at the User's Guide documentation on both 'apiNamespace' and 'actionsNamespace'.

...

Note on JDK 1.4 support
We have decided not to support JDK 1.4.

Unfortunately, we use many 1.5 features, especially generics.


Besides, we rely on several libraries that are 1.5 specific, such as Gson. We are very happy with Gson's performance and flexibility, and we feel it would be an important loss for DirectJNgine users not to use it for JSON handling.

...

If you want to take a look at the main DirectJNgine features, I recommend you take some time to read prior postings related to beta and RC versions in this thread, or just take a look at the "Features" chapter in the User's Guide.

...

Regards,

Pedro agulló

J@y
30 Jul 2009, 7:49 AM
So great to hear this news!

cheers!:))

mediacept
30 Jul 2009, 10:08 AM
Thank you for the final 1.0 version. Now we can continue to use DirectJNgine and looking ahead.

Thank you to this feature that resolves an OpenJDK bug in Ubuntu (from the user guide, page 37):


By the way, it is highly unlikely that minification fails: we use the YUI ompressor, a very well tested minifier. However, if the YUI Compressor raises some exception or reports some error, we make sure that the minified file will contain at least standard code, so that your application does not break because there is no “-min.js” file.
Good continuation.

dweller
30 Jul 2009, 10:38 PM
The paramsAsHash: true option is not supported, because I felt it will force us to receive values of unknown types, and I was concerned we might end up writing Java code that receives Object parameters all around (unknow type=> need to use Object as parameter type=> we loose Java's type safety) .

Type safety is one of the reasons for using Java at the server side, else why not using a more dynamic server side language?

Therefore, I'm trying to do writing that kind of code difficult -but not impossible.

That said, can you please provide a pair of concrete use cases in which paramsAsHash:true is needed? Will be glad to re-check my assumptions.

And, can you write here your client side call to 'load'?

I feel it is possible to get a great degree of flexibility without having to use the paramsAsHash: true thing.

Regards,

Pedro

eg.
Query data by different condition,and parameters number maybe one or more.
yes,we can handle this in clide-side code,but it's better to handle in server-side code.

permitted receive dynamic parameters in server-side code,there will be more flexibility.

Georgioa
31 Jul 2009, 1:14 AM
This is nice !!=D>

Thanks !

mct
31 Jul 2009, 2:48 AM
Hi,
I have a question for the ExtJS team:

Allowing that the DirectJNgine is in the final and stable release, can you add please in the Ext.Direct Pack (on ExtJS download page) a java folder with DirectJNgine (as cfml, DotNet, php and ruby) ?

Thank you for your response.

pagullo
2 Aug 2009, 10:13 PM
eg.
Query data by different condition,and parameters number maybe one or more.
yes,we can handle this in clide-side code,but it's better to handle in server-side code.

permitted receive dynamic parameters in server-side code,there will be more flexibility.

I think that you will probably want to give a try to direct JSON handling: take a look at chapter 11 in the User's Guide.

Georgioa
3 Aug 2009, 7:44 AM
Hi

I lost lot of time on my DirectStore this afternoon, but i dont known if it is a bug.

So i have my store which call my method. This is ok.

My remote method is :


@DirectMethod
public Status getLastStatus(){
return StatusList.getLast();
}

and returns an objet like this :


protected class Status{

private String message;
private Date time;
private int avancement;
......

}So server response is :

{"result":{"message":"test2","time":"3 août 2009 17:37:24","avancement":6},
"tid":2,"action":"ThreadStatus","method":"getLastStatus","type":"rpc"}

but my direct store needs something like :

{"result":[{"message":"test2","time":"3 août 2009 17:37:24","avancement":6}],
"tid":2,"action":"ThreadStatus","method":"getLastStatus","type":"rpc"}

If my method return a List<Status>, it is ok, but do we need to "encapsulate" objects to send them to the store?

By the way, this happens when a method returns only one object, and not a list of object.....

pagullo
3 Aug 2009, 8:31 AM
ExtJs guys have implemented DirectStore that way: it has to receive a JSON array, which it will turn into a javascript array.

Therefore you must return from Java an array or something that can be converted to a JSON array, such as a list. Not a DirectJNgine issue at all.

Regards,

Pedro Agulló.

Georgioa
3 Aug 2009, 10:22 AM
Ok, this is not a problem.

Thanks !

techstudios
3 Aug 2009, 8:50 PM
Does djn provide any approach to get HttpServletRequest and HttpSession object?

pagullo
3 Aug 2009, 11:40 PM
We don't.

Depending on what you need, you might be able to handle your needs by creating a servlet class that extends DirectJNgine's servlet.

Can you please provide additional information on how you want to use this, and why? Just for the record...

Regards,

Pedro.

techstudios
4 Aug 2009, 7:23 AM
We don't.

Depending on what you need, you might be able to handle your needs by creating a servlet class that extends DirectJNgine's servlet.

Can you please provide additional information on how you want to use this, and why? Just for the record...

Regards,

Pedro.

I think providing this would be very nice and helpful for programing

one of the reasons we use remoting is to make js to call POJO directly instead of calling a servlet, by providing an approach to retrieve HttpServletRequest and ServletContext, the POJO can easy to get/set attributes in session or application scope without passing the servlet as parameter to the method

one example is Flex, if you look at it's messaging/remoting api, there is a class flex.messaging.FlexContext, which provide methos to get HttpServletRequest , HttpServletResponse, ServletConfig and ServletContext, very convenient for programing

Imaging if we have a DjnContext, in the DirectStoreDemo, we can do this:


@DirectMethod
public List<Experience> djn_loadExperienceData() {
List<Experience> items = new ArrayList<Experience>();
Collections.addAll( items,
new Experience( "1990", "", "Programming, design and analysis in many projects, using Java, C#, C++, Smalltalk, Delphi, C"),
new Experience( "1992", "1994", "Develop Object Oriented Databases"),
new Experience( "1994", "", "More than 80 <b>articles published</b> in Delphi Magazine, Solo Programadores, Programacion Actual, etc."),
new Experience( "1997", "", "<b>Leading Developer and Architect</b> in many projects"),
new Experience( "2001", "2004", "<b>Team leader</b> of a team development a multidimensional database product"),
new Experience( "2002", "2003", "Development of an <b>ADO.NET driver</b> in C# for a multidimensional database (HiSpins)"),
new Experience( "2003", "", "Consulting in <b>Agile Programming</b> and <b>TDD</b>"),
new Experience( "2006", "", "Creation and direction of an <b>Agile Development Team</b>"),
new Experience( "2007", "", "Implementation of <b>BzNgine</b>, a framework for TDD of business classes, JPA based (Proprietary)"),
new Experience( "2009", "", "Implementation of proof of concept for a framework based on Wicket, <b>WiNgine</b> (Proprietary)"),
new Experience( "2009", "", "Implementation of <b>DirectJNgine</b> for ExtJs (OpenSource)"),
new Experience( "", "", "...other projects and skills")
);

//store the data in session scope, can be retrieved later
DjnContext.getHttpRequest().getSession().setAttribute("EXPERIENCE_DATA", items);

return items;
}

asgillett
4 Aug 2009, 8:24 PM
I don't know how to build a complex java web application without storing state in the HttpSession.

There are a few ways to do this using the magic of ThreadLocal variables. I use a servlet filter with a static "getHttpSession" methid:



public class SessionFilter implements Filter
{
private static ThreadLocal<HttpSession> sessionHolder = new ThreadLocal<HttpSession>();

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
if (req instanceof HttpServletRequest)
sessionHolder.set(((HttpServletRequest)req).getSession());
chain.doFilter(req, resp);
sessionHolder.set(null);
}

public static HttpSession getHttpSession() {
return sessionHolder.get();
}
...

and in my web.xml:


<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>your.package.SessionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<servlet-name>DjnServlet</servlet-name>
</filter-mapping>


alternatively, you can extend the servlet class and do much the same thing, wrapping the doGet and doPost methods:



public class MyServlet extends DirectJNgineServlet
{
private static ThreadLocal<HttpSession> sessionHolder = new ThreadLocal<HttpSession>();

public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
sessionHolder.set(req.getSession());
super.doGet(req, resp);
sessionHolder.set(null);
}
...


Andrew

Edit: fixed an embarrassing stack overflow in the servlets call to doFilter().

pagullo
4 Aug 2009, 10:15 PM
Completely agree, a filter + ThreadLocal is probably be the way to go for this stuff, so that it is not coupled in any way to DirectJNgine.

BTW: in this scenario, you should be careful if you are going to support the multithreaded handling of batched json requests built into DirectJNgine. Just disabling this via configuration might be a sensible approach to make your life easier.

...

That said, I am trying to keep DirectJNgine as focused as possible: to me, DirectJNgine mission is to provide the glue between ExtJs and server side Java.

The functionality you mention is orthogonal to DJN's purpose, so (at this moment) I do not plan to provide it. Should not be a problem, as you can get it independently of DJN.

Regards,

Pedro.

pagullo
5 Aug 2009, 10:47 PM
I have found that there seems to be some trouble figuring how to pass parameters to retrieve data using a DirectStore with DirectJNgine, so I have decided to add an example.

Here is an extract from the addition that will go into the next release User's Guide:




Passing parameters to DirectStore’s directFn
In real life, you will have to pass some parametert to your directFn method. You can do this in several ways:

• Use the DirectStore baseParams configuration property: lookup argFromBaseParams in the example code below to learn how to do this.
• Use the load method’s params argument: lookup argPassedInLoadCall in the example code to check how to do this.
• Add the parameter to the options object received by the DirectStore beforeload method: lookup argPassedInBeforeLoadEvent to learn how to do this.

Here is the javascript source code for the DirectJNgine test method demonstrating how to use this:


test_loadWithArguments : function() {
var myStore = new Ext.data.DirectStore( {
paramsAsHash:false,
root:'items',
paramOrder: ['argFromBaseParams', 'argPassedInLoadCall',
'argPassedInBeforeLoadEvent'],
totalProperty : 'rowCount',
directFn: DirectStoreTest.test_loadWithArguments,

idProperty:'id',
fields: [
{name: 'id' },
{name: 'name'}
],
listeners: {
beforeload : function(store, options) {
options.params.argPassedInBeforeLoadEvent = false
},
load: function(s, records){
Djn.Test.check( "test_loadWithArguments", records.length === 2,
"If there is an error, this will never be called: a " +
"timeout should happen if there is some error!" );
}
},
baseParams: {argFromBaseParams:'aValue'}
});

myStore.load({
params: {
argPassedInLoadCall: 34
}
});
}

Remember that you must set paramsAsHash to false. Besides, you must specify the order in which the parameters will be passed using the DirectStore paramOrder configuration parameter.
Here is the server side test method:


@DirectMethod
public DirectStoreResult djn_test_loadWithArguments(
String argFromBaseParams, int argPassedInLoadCall,
boolean argPassedInBeforeLoadEvent )
{
if( !argFromBaseParams.equals("aValue") || argPassedInLoadCall != 34 ||
argPassedInBeforeLoadEvent ) {
throw new DirectTestFailedException(
"Did no receive expected values");
}

Output[] result = new Output[2];
result[0] = new Output();
result[0].id = 99;
result[0].name = "name1";

result[1] = new Output();
result[1].id = 100;
result[1].name = "name2";

DirectStoreResult r = new DirectStoreResult( result, 347);
return r;
}
Passing unknown parameters to DirectStore’s directFn
If you need to pass unknown parameters (i.e, parameters whose name you don’t know beforehand), you will need to set the paramsAsHash to true, and then write a direct JSON handling method.

Hope this helps

dweller
6 Aug 2009, 1:57 AM
I have found that there seems to be some trouble figuring how to pass parameters to retrieve data using a DirectStore with DirectJNgine, so I have decided to add an example.

Here is an extract from the addition that will go into the next release User's Guide:


Hope this helps

I understand pass known parameters to retreve data using a DirectStore with DirectJNgine.

I try to pass unknown parameters,
here is javascript source code:


var experienceStore = new Ext.data.DirectStore( {
paramsAsHash:true,
root:'items',
totalProperty : 'rowCount',
directFn: DirectStoreDemo.loadExperienceData,
idProperty:'id',
fields: [
{name: 'id' },
{name: 'name'},
{name: 'experience.startDate'},
{name: 'experience.endDate'},
{name: 'experience.description'}
],
listeners: {
load: function(s, records){
Ext.MessageBox.alert( "Information", "Loaded " + records.length + " 记录");
}
},
paramsNames : {
start : "start",
limit : "limit",
sort : "sort",
dir : "dir"
},
baseParams : {
start : 1,
limit : 10,
sort : "id",
dir : "ASC"
}
});here is java code:

public DirectStoreResult loadExperienceData(JsonArray data) {
System.out.println("data:"+data);
for (int i = 0; i < data.size(); i++) {
System.out.println(data.get(i));
}
List<Person> items = new ArrayList<Person>();
Collections.addAll( items,...);


return new DirectStoreResult(items,100);
}but debug info is:
2009-08-06 17:47:16 DEBUG JsonRequestProcessor:81 - Request data (JSON)=>{"actio
n":"DirectStoreDemo","method":"loadExperienceData","data":[{"start":1,"limit":10
,"sort":"id","dir":"ASC","argPassedInLoadCall":"34"}],"type":"rpc","tid":2}
data:[]

loadExperienceData method received data is null

can you tell me how to retrieve unknown parameters,or provide an example illustrating how to pass unknown parameters.

thanks!

pagullo
6 Aug 2009, 5:27 AM
First of all, I am assuming that all of us have DJN 1.0 final installed and are not using release candidates or even 0.8... - direct JSON handling methods were added to 1.0 final.

...

I miss the call to to load in your post. Are you passing additional parameters there?

On the other hand, the paramsNames config property in your code should be paramNames -but I think it is not needed here.

And, how did you define DirectStoreResult? You need to be very careful about what you return, and when. You need to check the format Direct needs in a given context, don't assume you can just pick some data definition I defined for an example and use it in a different context, or that example code is production quality code.

Please, send the complete Java and Javascript code, and I'll do my best to check it.

...

I have taken a good look at your code, modifying the djn_test demo in an attempt to make it similar, and it works. Try it, as follows:

Javascript code: modify DirectStoreDemo.js so that the experienceStore is created and loaded with data as follows,



var experienceStore = new Ext.data.DirectStore( {
paramsAsHash:true,
root:'',
directFn: DirectStoreDemo.loadExperienceData,
idProperty:'description',
fields: [
{name: 'startDate'},
{name: 'endDate'},
{name: 'description'}
],
listeners: {
load: function(s, records){
Ext.MessageBox.alert( "Information", "Loaded " + records.length + " records");
}
},
baseParams : {
start : 1,
limit : 10,
sort : "id",
dir : "ASC"
}
});

experienceStore.load();
// ... other Javascript code not relevant
Java code: modify DirectStoreDemo.java so that the djn_loadExperienceData looks like this,



@DirectMethod
public List<Experience> djn_loadExperienceData( JsonArray data) {
assert data != null;
System.out.println( "data:" + data );
for (int i = 0; i < data.size(); i++) {
System.out.println(data.get(i));
}

List<Experience> items = new ArrayList<Experience>();
// ...Remaining code like the original implementation!

return items;
}
Try this code and let me know whether it works

Regards

vlagorce
11 Aug 2009, 5:36 AM
Hi ,

First I would like to thank the developer(s) for this great Api !!

I have passed DirectJNgine under spring to avoid declaration in web.xml. It works fine.

I loose some feature; grouping Action by Api, using actionsNamespace,.. So I use my proper annotation in addition of @DirectAction, @DirectMethod,..


My class looks like this.


@Component // spring scan
@DirectAction(action = "MyTestAction")
@MyDirectAction(api = "myApi", ns = "MyActionNs")
public class TestAction implements IDirectAction {

@DirectMethod()
public String hello(String arg) {
return "hello wolrd !";
}

}
I regrets to have two annotation for 'the same things'.@DirectAction and @MyDirectAction
I tried to override Registry.java or access the map to set action and method defined with on my annotation but every useful method or constructor are private...


In the future version could the Registry have an interface or some method to access Api, Action,Method,... map ?


Regards,
Vincent

J@y
11 Aug 2009, 6:59 PM
I have a question when developing the web app.

We know that Djn will generate the api.js once the server starts/restarts, however the auto deployment feature of eclipse will remove the api.js in the web server pool if you did any changes on any files of your web app.

My question is, is there a way to call the Djn to generate the api.js manually?
eg: include it in the ant build script.

edit: I found that this problem only happened to Glassfish.......
while Tomcat works fine.

dweller
11 Aug 2009, 7:55 PM
First of all, I am assuming that all of us have DJN 1.0 final installed and are not using release candidates or even 0.8... - direct JSON handling methods were added to 1.0 final.

...

I miss the call to to load in your post. Are you passing additional parameters there?

On the other hand, the paramsNames config property in your code should be paramNames -but I think it is not needed here.

And, how did you define DirectStoreResult? You need to be very careful about what you return, and when. You need to check the format Direct needs in a given context, don't assume you can just pick some data definition I defined for an example and use it in a different context, or that example code is production quality code.

Please, send the complete Java and Javascript code, and I'll do my best to check it.

...

I have taken a good look at your code, modifying the djn_test demo in an attempt to make it similar, and it works. Try it, as follows:

Javascript code: modify DirectStoreDemo.js so that the experienceStore is created and loaded with data as follows,



var experienceStore = new Ext.data.DirectStore( {
paramsAsHash:true,
root:'',
directFn: DirectStoreDemo.loadExperienceData,
idProperty:'description',
fields: [
{name: 'startDate'},
{name: 'endDate'},
{name: 'description'}
],
listeners: {
load: function(s, records){
Ext.MessageBox.alert( "Information", "Loaded " + records.length + " records");
}
},
baseParams : {
start : 1,
limit : 10,
sort : "id",
dir : "ASC"
}
});

experienceStore.load();
// ... other Javascript code not relevant
Java code: modify DirectStoreDemo.java so that the djn_loadExperienceData looks like this,



@DirectMethod
public List<Experience> djn_loadExperienceData( JsonArray data) {
assert data != null;
System.out.println( "data:" + data );
for (int i = 0; i < data.size(); i++) {
System.out.println(data.get(i));
}

List<Experience> items = new ArrayList<Experience>();
// ...Remaining code like the original implementation!

return items;
}
Try this code and let me know whether it works

Regards


I don't modify my code, and it works.
I guess djn rc1.0 upgrade to 1.0.

vlagorce
12 Aug 2009, 7:08 AM
In class CodeFileGenerator logger initialization seems to be wrong :



private static final Logger logger = Logger.getLogger(Registry.class);
instead of :



private static final Logger logger = Logger.getLogger(CodeFileGenerator.class);




For my previews ask I have rewrite a Registry class with same package and Name. It works perfectly !

cwilliso
14 Aug 2009, 2:05 PM
Hi Pedro -

I really like your directJNgine product, but have a couple of questions/concerns :

1.) I didn't really feel comfortable with the amount of server init params I must enter into the web.xml file to configure a large app. Is there any way to integrate your product with Spring to make the wiring/config easier? Ideally there would be 1 single entry in the web.xml file for the engine, and then a separate application-Context.xml with all of the standard configured spring beans. Thoughts?

2.) Are there more sample apps built with directJNgine & ExtJS that I could take a look at?

Thanks !
Chris.

vlagorce
16 Aug 2009, 11:48 PM
Hi cwilliso,

Like you, I prefer to have a simple web.xml without params.
In my project I make the following modification to use spring

1) create a factory class with autowired list attribute typed with and interface (IDirectAction). Add and autowired attribut for the globalConfiguration.

2)rewrite the servlet and use your factory to have the Registry

3) All your action must implement the interface you use for the actionList defined in the factory. Add the @Component annotation to allow the autowiring. Use the directJNgine annotation on method and action if needed.

4)add <context:component-scan .... /> in your spring configuration and create the bean for the globalConfiguration with your params


That's all.

If you want to keep the possibility of grouping action by Api the way to do is to rewrite Registry and use your own annotation..

mauro_monti
20 Aug 2009, 7:27 AM
Can you post your Spring Solution. I'm trying to integrate @DirectAction annotation with the Spring @Controller and @Autorwired properties, but i have no luck.

It seems that the @Controller and @DirectAction makes differents instances...o f the same class..

Bye!. Mauro

pagullo
21 Aug 2009, 2:08 AM
In class CodeFileGenerator logger initialization seems to be wrong :



private static final Logger logger = Logger.getLogger(Registry.class);
instead of :



private static final Logger logger = Logger.getLogger(CodeFileGenerator.class);
For my previews ask I have rewrite a Registry class with same package and Name. It works perfectly !


Fixed this as well as a similar problem with RegisteredPollMethod's logger.

Thanks!

pagullo
21 Aug 2009, 3:33 AM
I have a question when developing the web app.

We know that Djn will generate the api.js once the server starts/restarts, however the auto deployment feature of eclipse will remove the api.js in the web server pool if you did any changes on any files of your web app.

My question is, is there a way to call the Djn to generate the api.js manually?
eg: include it in the ant build script.

edit: I found that this problem only happened to Glassfish.......
while Tomcat works fine.

Not a DirectJNgine issue, but specific to a certain IDE+web-server combination, so what we need is some kind of workaround for your environment. I think your Eclipse tool is being a bit too agressive!

Unfortunately, there is no practical way to force DJN to check the .js file on every request. I did that on purpose, for performance reasons: we would need to check whether the file exists (not very expensive), and whether it is up to date or not, a much more expensive operation. I don't want to do that check for every request.

...

A possible workaround is to restart your web app via ant tasks.

In fact, what I do is to set my context reloadable attribute to true, and then I modify my web.xml adding a blank line, so that my app is reloaded. Easy to do with an ant task and probably "portable" among many web servers, as it does not need web-server specific ant tasks to restart the app.

I hope this works in your environment. Let us know, please.

mauro_monti
21 Aug 2009, 6:38 AM
Hola Pedro,

Veo que estás en BCN, así que creo que puedo cambiar el idioma por un momento (me siento más cómodo :D).

Queria hacerte la siguiente consulta. Estoy tratando de integrar DirectJNgine con Spring MVC y he tenido algunos problemas para utilizar las anotaciones @DirectAction y @DirectMethod.

El problema que he tenido es que al realizar una llamada a una clase Anotada con DirectAction, y que a su vez esta anotada como un Controller de Spring; DirectJNgine crea sus propias instancias de la clase (Por lo poco que he visto en el codigo, esto se realiza en la clase Registry... no?), las cuales son diferentes a las instancias que mantiene el contenedor de Spring, lo que hace que la inyeccion de dependencias no funcione.

Lo que queria saber es si conoces algun desarrollo para intentar integrar estos dos frameworks (aunque ya me he puesto a tirar algunas líneas de código, no quiero reinventar la rueda). Mi idea hasta el momento es hacer un Wrapper del Servlet de DirectJNgine que tenga referenciado el contexto de Spring, y sobreescribir los métodos que crean las instancias de las clases a exponer, para obtenerlas directamente desde el contenedor de Spring.

Bueno por último, felicitarte por el trabajo realizado con DirectJngine... es excelente.
Saludos.
Mauro.

wguan
23 Aug 2009, 7:22 PM
Can you post your Spring Solution. I'm trying to integrate @DirectAction annotation with the Spring @Controller and @Autorwired properties, but i have no luck.

It seems that the @Controller and @DirectAction makes differents instances...o f the same class..

Bye!. Mauro

I also got this problem, anyone can help?

vlagorce
24 Aug 2009, 1:19 AM
I'm sorry to reply a bit late...

So my spring 'adaptation'.

I have write my own annotation, but they have the same implementation as DirectJNgine version.

First All my action implement an empty interface IDirectAction. And I use @component on it.



import org.springframework.stereotype.Component;

import sdbx.djn.direct.action.IDirectAction;
import sdbx.djn.direct.annotations.DirectAction;
import sdbx.djn.direct.annotations.DirectMethod;

@Component
@DirectAction(action = "MyTestAction")
public class TestAction implements IDirectAction {

@DirectMethod()
public String hello(String arg) {
return "hello "+arg;
}

}The autowiring will put this action in a class called DirectDomain. It's aim to generate the Registry.class.

DirectConfiguration is just the bean where I put my configuration it use default configuration present in GlobalConfiguration.

The servlet name is used to generate the api name.


/**
* Api initialiser
*
* @author vlagorce
*/
public class DirectDomain {

/**
* Action container and js api genetator
*/
private Registry registry;

/**
* global Configuration used in runtime
*/
private GlobalConfiguration globalConfiguration;

/**
* redefined configuration only used when application start to redefine GlobalConfiguration
*/
@Autowired(required = false)
private DirectConfiguration directConfiguration;

/**
* List of actions to be published in js Api
*/
@Autowired
private List<IDirectAction> actions;

/**
* @return the registry
*/
/*package*/Registry getRegistry() {
return registry;
}

/**
* @return the configuration
*/
/*package*/GlobalConfiguration getGlobalConfiguration() {
return globalConfiguration;
}

/**
* Registry initialization
* @param servlet
*/
/*package*/void initialize(HttpServlet servlet) {
ServletContext context = servlet.getServletContext();
String domainName = servlet.getServletName();
String providerUrl = servlet.getInitParameter(DirectServlet.PROVIDER_URL_KEY);

// config initilization
if (this.directConfiguration == null) {
this.directConfiguration = new DirectConfiguration();
}
this.globalConfiguration = this.directConfiguration.createGlobalConfiguration(providerUrl);
// directConfiguration
directConfiguration = null; // no more needed

//build js api relative path
String JsFolder = servlet.getInitParameter(DirectServlet.API_JS_FOLDER_KEY);
StringBuilder apiJSRelativePath = new StringBuilder();
if (JsFolder != null) {
apiJSRelativePath.append(JsFolder);
}
apiJSRelativePath.append("/");
apiJSRelativePath.append(domainName);
apiJSRelativePath.append("-api.js");

// create apiconfiguration
List<ApiConfiguration> apis = new ArrayList<ApiConfiguration>();
if (this.actions != null) {
List<Class<?>> listActionClass = new ArrayList<Class<?>>(this.actions.size());
for (IDirectAction action : this.actions) {
listActionClass.add(action.getClass());
}
/*
* If you want to allow grouping action by api you can do it here ! You have * to define you own annotation and add params you need.
*/
apis.add(new ApiConfiguration(domainName, context.getRealPath(apiJSRelativePath.toString()), domainName, "", listActionClass));


}
this.registry = new Registry(this.globalConfiguration, apis);
}
}
I have rewrite the registry to use my own annotation but it's facultativ. An interesting modification coold be the use of org.springframework.core.annotation.AnnotationUtils.findAnnotation() to find annotation through inheritance instead of getAnnotation().

I rewrite the servlet too. I use the DirectDomain class to generate Registry in it.


package sdbx.djn.direct;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.web.context.ContextLoader;

import com.softwarementors.extjs.djn.EncodingUtils;
import com.softwarementors.extjs.djn.ServletUtils;
import com.softwarementors.extjs.djn.StringUtils;
import com.softwarementors.extjs.djn.Timer;
import com.softwarementors.extjs.djn.jscodegen.CodeFileGenerator;
import com.softwarementors.extjs.djn.router.RequestRouter;
import com.softwarementors.extjs.djn.router.RequestType;
import com.softwarementors.extjs.djn.router.processor.RequestException;
import com.softwarementors.extjs.djn.router.processor.poll.PollRequestProcessor;
import com.softwarementors.extjs.djn.router.processor.standard.form.upload.UploadFormPostRequestProcessor;

/**
* Input servlet for direct js call
* @author vlagorce
*/
public class DirectServlet extends HttpServlet {

/** serialVersionUID */
private static final long serialVersionUID = 8535973777824527371L;

/** spring beanName prefix key */
private static final String PREFIX_DOMAIN_BEAN_NAME = "direct.domain.";

/** Mandatory param to define servlet mapping in generated js Api */
public static final String PROVIDER_URL_KEY = "direct.provider.url";

/** Facultativ param to define the destination folder for generated js Api */
public static final String API_JS_FOLDER_KEY = "direct.api-js.folder";

private Logger logger;

/**
* Action container
*/
private DirectDomain domain;

/**
* Spring Context
*/
private ContextLoader contextLoader;

/**
* action dispatcher
*/
private RequestRouter processor;

/**
* fileUpload servlet
*/
private ServletFileUpload upload;

/**
* unique id for the NDC class. Allow to group log with multi thread
*/
private long id = 1000; // It is good we will get lots of ids with the same number of digits...

@Override
public void destroy() {
super.destroy();
if (this.contextLoader != null) {
this.contextLoader.closeWebApplicationContext(getServletContext());
}
}

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
doPost(request, response);
}

@Override
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
NDC.push("rid: " + Long.toString(getUniqueRequestId()));
try {
Timer timer = new Timer();
try {
if (logger.isTraceEnabled()) {
String requestInfo = ServletUtils.getDetailedRequestInformation(request);
logger.trace("Request info: " + requestInfo);
}

response.setContentType("text/html"); // MUST be "text/html" for uploads to work!
String requestEncoding = request.getCharacterEncoding();
// If we don't know what the request encoding is, assume it to be UTF-8
if (StringUtils.isEmpty(requestEncoding)) {
request.setCharacterEncoding(EncodingUtils.UTF8);
}
response.setCharacterEncoding(EncodingUtils.UTF8);

RequestType type = getFromRequestContentType(request);
// Dispatch
switch (type) {
case FORM_SIMPLE_POST:
this.processor.processSimpleFormPostRequest(request.getReader(), response.getWriter());
break;
case FORM_UPLOAD_POST:
processUploadFormPost(request, response);
break;
case JSON:
this.processor.processJsonRequest(request.getReader(), response.getWriter());
break;
case POLL:
this.processor.processPollRequest(request.getReader(), response.getWriter(), request.getPathInfo());
break;
}
} finally {
timer.stop();
timer.logDebugTimeInMilliseconds("Total servlet processing time");
}
} finally {
NDC.pop();
}
}

/**
* Return the ContextLoader used by this servlet.
*
* @return the current ContextLoader
*/
public ContextLoader getContextLoader() {
return this.contextLoader;
}

/**
* @return the domain
*/
public DirectDomain getDomain() {
return domain;
}

@Override
public void init() throws ServletException {
logger = Logger.getLogger(DirectServlet.class);
//Log4jWebConfigurer.initLogging(getServletContext());
if (ContextLoader.getCurrentWebApplicationContext() == null) {
this.contextLoader = createContextLoader();
// test context spring exist
if (ContextLoader.getCurrentWebApplicationContext() != null)
this.contextLoader.initWebApplicationContext(getServletContext());
}
// create domain if not exist
if (getDomain() == null) {
domain = createDomain();
}
// inject domain in spring context
if (domain != null) {
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) ContextLoader.getCurrentWebApplicationContext()
.getAutowireCapableBeanFactory();
beanFactory.autowireBeanProperties(domain, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
beanFactory.initializeBean(domain, PREFIX_DOMAIN_BEAN_NAME + getServletName());
domain.initialize(this);
}

// create api file and initialize direct processor
try {
CodeFileGenerator.updateApiFiles(domain.getRegistry());
processor = new RequestRouter(domain.getRegistry(), domain.getGlobalConfiguration());
} catch (IOException ex) {
ServletException e = new ServletException("Unable to create DirectJNgine API files", ex);
logger.fatal(e.getMessage(), e);
throw e;
}
super.init();
}

/**
* Create the ContextLoader to use. Can be overridden in subclasses.
*
* @return the new ContextLoader
*/
protected ContextLoader createContextLoader() {
return new ContextLoader();
}

protected DirectDomain createDomain() {
DirectDomain domain = new DirectDomain();
return domain;
}

@SuppressWarnings("unchecked")
// Unfortunately, parseRequest returns List, not List<FileItem>
private List<FileItem> getFileItems(HttpServletRequest request) throws FileUploadException {
if (upload == null) {
upload = UploadFormPostRequestProcessor.createFileUploader();
}

return this.upload.parseRequest(request);
}

private RequestType getFromRequestContentType(HttpServletRequest request) {
assert request != null;

String contentType = request.getContentType();
String contentTypeLowercase = "";
if (contentType != null) {
contentTypeLowercase = contentType.toLowerCase();
}

String pathInfo = request.getPathInfo();

if (!StringUtils.isEmpty(pathInfo) && pathInfo.startsWith(PollRequestProcessor.PATHINFO_POLL_PREFIX)) {
return RequestType.POLL;
} else if (contentTypeLowercase.startsWith("application/json")) {
return RequestType.JSON;
} else if (contentTypeLowercase.startsWith("application/x-www-form-urlencoded") && request.getMethod().toLowerCase().equals("post")) {
return RequestType.FORM_SIMPLE_POST;
} else if (ServletFileUpload.isMultipartContent(request)) {
return RequestType.FORM_UPLOAD_POST;
} else {
String requestInfo = ServletUtils.getDetailedRequestInformation(request);
RequestException ex = RequestException.forRequestFormatNotRecognized();
logger.error("Error during file upload: " + ex.getMessage() + "\nAdditional request information: " + requestInfo, ex);
throw ex;
}
}

private synchronized long getUniqueRequestId() {
return this.id++;
}

private void processUploadFormPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
this.processor.processUploadFormPostRequest(getFileItems(request), response.getWriter());
} catch (FileUploadException e) {
this.processor.handleFileUploadException(e);
}
}

}
That's all for the implementation.

beans definition

<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName" xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">


<context:annotation-config />
<context:component-scan base-package="test.sdbx.djn.sandbox.action" />

<bean id="directConfiguration" class="sdbx.djn.direct.DirectConfiguration">
<property name="debug" value="false"/>
<property name="minify" value="true"/>
</bean>

</beans>web.xml


<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:direct-beans-definitions.xml,/WEB-INF/applicationContext.xml
</param-value>
</context-param>


<servlet>
<servlet-name>ApiExtsdbx</servlet-name>
<servlet-class>sdbx.djn.direct.DirectServlet</servlet-class>
<init-param>
<param-name>direct.provider.url</param-name>
<param-value>/djn</param-value> /*there isn't other way to have this value in the servlet*/
</init-param>
<init-param>
<param-name>direct.api-js.folder</param-name>
<param-value>/js/directApi</param-value> /*if you want specify the folder where the api-js will be generated*/
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>ApiExtsdbx</servlet-name>
<url-pattern>/djn/*</url-pattern>
</servlet-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<welcome-file-list>
<welcome-file>
index.html
</welcome-file>
</welcome-file-list>
</web-app> I give you the full code because I do not have enougth time to just extract the modification and well comment.

I hope that will help you anyway.

pagullo
24 Aug 2009, 2:52 AM
Hi, Vincent.

I am DirectJNgine author.

First of all, I would like to thank you for your contribution. I can't help but notice that Spring support seems to be important to many in the community!

I would like to make a comment on how to customize the DJN servlet, to minimize potential problems and maximize value for the community.

As DJN evolves, the DJN servlet might change: if custom functionality (like Spring support) is attained by inheriting from it, it will be much more likely that things keep working in the face of new DJN features or bug fixes. If inheritance is not used, then cut & paste will be needed - a maintenance nightmare.

As an example, in your code, it feels as if all that's needed is to inherit from the base servlet, override the init method and maybe make some private base methods protected and/or add some protected methods to wrap field access -haven't tried, though.

Maybe you or some other person can give this a try, and tell us whether it works, and the required modifications to the base servlet. Unfortunately, I'm not a Spring user, so I can't easily do it and test that things really work.

If inheritance does not work for some reason, then I will consider modifying the base servlet so that DJN users can customize it easily.

Regards

pagullo
24 Aug 2009, 2:57 AM
Hola Pedro,

Veo que estás en BCN, así que creo que puedo cambiar el idioma por un momento (me siento más cómodo :D).

Queria hacerte la siguiente consulta. Estoy tratando de integrar DirectJNgine con Spring MVC y he tenido algunos problemas para utilizar las anotaciones @DirectAction y @DirectMethod.

El problema que he tenido es que al realizar una llamada a una clase Anotada con DirectAction, y que a su vez esta anotada como un Controller de Spring; DirectJNgine crea sus propias instancias de la clase (Por lo poco que he visto en el codigo, esto se realiza en la clase Registry... no?), las cuales son diferentes a las instancias que mantiene el contenedor de Spring, lo que hace que la inyeccion de dependencias no funcione.

Lo que queria saber es si conoces algun desarrollo para intentar integrar estos dos frameworks (aunque ya me he puesto a tirar algunas líneas de código, no quiero reinventar la rueda). Mi idea hasta el momento es hacer un Wrapper del Servlet de DirectJNgine que tenga referenciado el contexto de Spring, y sobreescribir los métodos que crean las instancias de las clases a exponer, para obtenerlas directamente desde el contenedor de Spring.

Bueno por último, felicitarte por el trabajo realizado con DirectJngine... es excelente.
Saludos.
Mauro.

Hola, Mauro.

¿Tú también estás por BCN? ¿A qué te dedicas? (si acaso, mándame un mensaje privado para no "ensuciar" el foro ;) )

No conozco de ninguna solución completamente testeada, aunque veo que algunas personas proporcionan código fuente para trabajar con Spring: si lo usas, no olvides dar feedback a la comunidad (en inglés, je, je)

Saludos, y suerte!

vlagorce
24 Aug 2009, 3:18 AM
Hi, Vincent.

I am DirectJNgine author.

First of all, I would like to thank you for your contribution. I can't help but notice that Spring support seems to be important to many in the community!

I would like to make a comment on how to customize the DJN servlet, to minimize potential problems and maximize value for the community.

As DJN evolves, the DJN servlet might change: if custom functionality (like Spring support) is attained by inheriting from it, it will be much more likely that things keep working in the face of new DJN features or bug fixes. If inheritance is not used, then cut & paste will be needed - a maintenance nightmare.

As an example, in your code, it feels as if all that's needed is to inherit from the base servlet, override the init method and maybe make some private base methods protected and/or add some protected methods to wrap field access -haven't tried, though.

Maybe you or some other person can give this a try, and tell us whether it works, and the required modifications to the base servlet. Unfortunately, I'm not a Spring user, so I can't easily do it and test that things really work.

If inheritance does not work for some reason, then I will consider modifying the base servlet so that DJN users can customize it easily.

Regards

I'am bit busy at the beginning of the week, but I will try. I can't remember why I don't extend the base servlet ..

pagullo
24 Aug 2009, 3:34 AM
Great! Thanks for volunteering ;)!

You probably found that you did not have access to things like the registry. You will need to perform small adjustments to the DJN servlet itself before you can inherit from it.

You can regenerate the library via ant, so that hoperfully that will not be much of a problem.

vlagorce
26 Aug 2009, 3:06 AM
I also got this problem, anyone can help?

Quote:
Originally Posted by mauro_monti https://www.extjs.com/forum/images/buttons/viewpost.gif (https://www.extjs.com/forum/showthread.php?p=376673#post376673)
Can you post your Spring Solution. I'm trying to integrate @DirectAction annotation with the Spring @Controller and @Autorwired properties, but i have no luck.

It seems that the @Controller and @DirectAction makes different instances...o f the same class..

Bye!. Mauro

I also got this problem, anyone can help?


A new Action instance is create on each action call.

The Action instance is create by the createActionInstance method in com.softwarementors.extjs.djn.router.dispatcher.Dispatcher.

Extends Dispatcher and implements the applicationContextAware interface to get action bean by using applicationContext.getBeansOfType(instanceClass);it's a map but there must be only one instance for each action

The next problem is that Dispatcher is instantiate in RequestRouter constructor and is not easily accessible. This class must be modified to.

It's just a quick fix.
As Pagullo says DJN evolves and rewriting full class will be a maintenance nightmare.

@pagullo
I don't forget to try better spring integration with some djn classes modification :)

vlagorce
4 Sep 2009, 7:42 AM
Great! Thanks for volunteering ;)!

You probably found that you did not have access to things like the registry. You will need to perform small adjustments to the DJN servlet itself before you can inherit from it.

You can regenerate the library via ant, so that hoperfully that will not be much of a problem.

Hi Pedro,

I almost finished modifications. It remains some test. There is not much change in DJN api.
I'll send you all sources may be next week.

I did not use ant task to generate jar, I've passed project under maven.

pagullo
6 Sep 2009, 11:22 PM
Great!

Think many users will be grateful for that.

BTW: I'm going to release an alpha that exposes a programmatic API this week, so that DirectJNgine can be configured programmatically. This opens the door to integrate your own annotation processing, etc., something I think you were interested in.

I wonder whether you will be interested in taking a look at the alpha to help define a good API for this functionality.

Regards

vlagorce
8 Sep 2009, 1:21 AM
Yes I'm interesting.

It's better if I can help you to allow spring usage on the next version especially if you implements programmatic configuration.

There are mainly 2 problems in the version 1.0 to use spring.

1- The traitement of configuration parameters is in two parts one in the servlet and the other in the globalConfiguration. I bypass it with an globalConfiguration factory in witch I set my params with spring.

2- Spring use singleton and the dispatcher class instantiate a new Action for each call ( except for static method). I extend the dispatcher to use ''spring bean container''.

I will send you the source at the end of the week.

It could be a good thing if you add some interface. For example RequestRouter, Registry, Configuration, Dispatcher..

Suppressing treatment in constructor and add protected init method (or an other solution). Because with inheritance we can't bypass it.

Regards,

pagullo
8 Sep 2009, 5:43 AM
I'm releasing DirectJNgine 1.1 alpha 1 today.

You can download it from http://code.google.com/p/directjngine/, as always.

The purpose of this early release is to help shape the programmatic interface for adding apis, actions, methods and poll methods, so that it can satisfy the needs of 90% of the advanced DJN users.

If anybody is interested in influencing the api, this is *the* moment to do it.

Take a look at the Adding actions and methods programmatically chapter in the User's Guide for an example of how to use the candidate api.

...

@Vincent

Great!

Maybe you can adapt what you have to run with the new version: should take very little time. I will be looking forward to your proposal for modifying DJN with new customization points, so that

a) Spring users can use DJN easily, without DJN having a dependency on Spring.
b) You can provide Spring support without worrying too much about me makeing changes in new versions of DJN that break your code.

From what you said, looks like it will be easy! Maybe minor changes to the servlet and some way to provide custom object instantiation -very easy, too.

Regards

J@y
8 Sep 2009, 11:27 AM
Nice release, thanks!

I have a question, although this is not related to DJN...

Do you know how to get the connection object or DirectStore?
Actually I want to abort the ajax request of DirectStore during the loading.
Is there anyway to handle the on-the-way request/response?

Thanks in advance!

pagullo
8 Sep 2009, 11:48 PM
The DirectStore ends up calling a method managed by a RemotingProvider. And, by taking a look at the source code in ext-all-debug.js, you will find that the connection used by a RemotingProvider is Ext.Ajax: see the Ext.direct.RemotingProvider doSend and processForm methods.

So maybe the way to abort an ongoing request is to call Ext.Ajax.abort().

Haven't tried this, though: you will have to try it to know whether this line of thought is right and it works.

Let us know what happens!

J@y
9 Sep 2009, 1:33 AM
The DirectStore ends up calling a method managed by a RemotingProvider. And, by taking a look at the source code in ext-all-debug.js, you will find that the connection used by a RemotingProvider is Ext.Ajax: see the Ext.direct.RemotingProvider doSend and processForm methods.

So maybe the way to abort an ongoing request is to call Ext.Ajax.abort().

Haven't tried this, though: you will have to try it to know whether this line of thought is right and it works.

Let us know what happens!

Thanks for your reply!

I think the API doc has missed something.......I can't find the doSend and processForm in the online API. But could be found in the source code.

let me try it tmr.

J@y
9 Sep 2009, 2:14 AM
Unfortunately it doesn't work...

I place the Ext.Ajax.abort() in the beforeload() listeners of store, so that before each request sent from the client, the store will 1st abort the previous request.

But nothing happened after I apply this change.

(The response time of the request is more than 5s)

pagullo
9 Sep 2009, 2:34 AM
Yup!

Maybe you will have a better chance to get an answer if you post the question in a different thread, as this one is likely to be checked only by peopled interested in DirectJNgine, and your question is not related to it.

J@y
9 Sep 2009, 2:51 AM
Yup!

Maybe you will have a better chance to get an answer if you post the question in a different thread, as this one is likely to be checked only by peopled interested in DirectJNgine, and your question is not related to it.

Actually I've asked the same question in different forum, but seems no one got the answers.

The connection object of DirectProxy is not exactly the same as other proxy object, so I can't kill the request by Ext.Ajax.abort(store.proxy.activeRequest) <---directproxy does not have activeRequest object...

anyway thanks for your help!

vlagorce
9 Sep 2009, 5:23 AM
I'm releasing DirectJNgine 1.1 alpha 1 today.

You can download it from http://code.google.com/p/directjngine/, as always.

The purpose of this early release is to help shape the programmatic interface for adding apis, actions, methods and poll methods, so that it can satisfy the needs of 90% of the advanced DJN users.

If anybody is interested in influencing the api, this is *the* moment to do it.

Take a look at the Adding actions and methods programmatically chapter in the User's Guide for an example of how to use the candidate api.

...

@Vincent

Great!

Maybe you can adapt what you have to run with the new version: should take very little time. I will be looking forward to your proposal for modifying DJN with new customization points, so that

a) Spring users can use DJN easily, without DJN having a dependency on Spring.
b) You can provide Spring support without worrying too much about me makeing changes in new versions of DJN that break your code.

From what you said, looks like it will be easy! Maybe minor changes to the servlet and some way to provide custom object instantiation -very easy, too.

Regards

It's done :)

The RegistryConfigurator is helpfull to use spring ;)

I've only make modification in RequestRouter, Dispatcher, DirectJNgineServlet.

I've override only Dispatcher, DirectJNgineServlet.

The scanAndRegisterAllKindsOfMethods in Scanner should be externalized. It's useFull to not rewrite the method extraction. I've made a static helper (ActionScanner) but I did not use in DJN I want your opinion.

The way I define the globalConfiguration with a 'factory' does not suit me. But now, I didn't find a better solution.

You can find it in the two zip attached to this reply.

...........


If people will make some test with this version I give you my test configuration.

example action


@Component
@DirectAction(action ="HelloAction")
public class TestAction implements IDirectAction {

@DirectMethod(method = "hello")
public String testMethod(String arg) {
return "hello " + arg + " !";
}

}
and an bean-config.xml like this




<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName"
xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:annotation-config />
<context:component-scan base-package="com.sdbx.sandbox.action" />
<context:component-scan base-package="com.extjs.djn.spring" />
<bean id="testApiConfiguration"
class="com.extjs.djn.spring.action.conf.impl.ActionApiConfiguration">
<property name="apiName" value="MyExtApiName" />
<property name="apiNamespace" value="MyExtApiNamespace" />
<property name="apiFolder" value="js/directApi" />
</bean>


</beans>
web.xml


<?xml version="1.0" encoding="ISO-8859-1"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:direct-beans-definitions.xml,/WEB-INF/applicationContext.xml
</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>directServlet</servlet-name>
<servlet-class>com.extjs.djn.spring.servlet.SpringDirectJNgineServlet</servlet-class>
<init-param>
<param-name>providersUrl</param-name>
<param-value>/djn</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>directServlet</servlet-name>
<url-pattern>/djn/*</url-pattern>
</servlet-mapping>

<welcome-file-list>
<welcome-file>
index.html
</welcome-file>
</welcome-file-list>
</web-app>

pagullo
9 Sep 2009, 11:37 PM
Will take an in-depth look at it asap :>

That said, on a first look it seems like the number of changes/additions will be very small, and overall everything looks good!

Now, so that I can see it in action, what additional JARs are needed? And, do you have an ant build file? Would be great!

Regards

vlagorce
10 Sep 2009, 12:26 AM
I did not use Ant :/ You will find bellow the dependency tree .

No additional Jar is need for the DJN modification.

djn dependency:tree
djn-spring dependency:tree




+- djn:djn:jar:1.1-alpha:compile
| +- log4j:log4j:jar:1.2.14:compile
| +- jargs:jargs:jar:1.0:compile
| +- commons-fileupload:commons-fileupload:jar:1.2.1:
| +- commons-io:commons-io:jar:1.4:compile
| +- com.google.code.gson:gson:jar:1.3:compile
| \- com.yahoo:yuicompressor:jar:2.4.2:compile
+- javax.servlet:servlet-api:jar:2.5:provided
+- org.springframework:spring-context:jar:2.5.6:compil
| +- aopalliance:aopalliance:jar:1.0:compile
| +- commons-logging:commons-logging:jar:1.1.1:compil
| +- org.springframework:spring-beans:jar:2.5.6:compi
| \- org.springframework:spring-core:jar:2.5.6:compil
\- org.springframework:spring-web:jar:2.5.6:compile


If you want I can give you the full eclipse projects . You should have maven or redefine buildpath to use it.

Regards

vlagorce
10 Sep 2009, 5:26 AM
A new idea

For my spring integration I'm passed through the RegistryConfiguration, but override the scanner could be a (better?) solution.

It's allow ..
- reuse mechanism to retrieve action and method (In my implementation I've duplicate a part of code (ActionScanner)).

- change annotation type (ex: use is own annotation with more params).

- change annotation detection (ex: spring allow to find annotation through inheritance contrary to myClass.getAnnotation() ) .

- change method name prefix.
To do that the Scanner instantiation should be done in a createMethod() and almost all method should be protected .

mauro_monti
15 Sep 2009, 6:51 AM
Hi Vlagorce,

I have to say that you are making an excelent work with the integration of DirectJNgine - Spring. I am making some test with the JARS, in the previous posts. It's looks very well.

I had some problems to configure the Api File and Folder. For example, if in my ApiActionConfiguration have:



<bean id="apiConfiguration" class="com.extjs.djn.spring.action.conf.impl.ActionApiConfiguration">
<property name="apiName" value="dst" />
<property name="apiNamespace" value="Ext.dst" />
<property name="apiFile" value="/dst/Api.js" />
</bean>


I get an IOException saying \dst\Api-debug.js' exists but is a directory...
Do you know how to solve this problem?...

On the other hand, i watched the class SpringRegistryConfiguration. Seems that registry actions, obviating the action paramete of the annotated class. Here is my contribution:

SpringRegistryConfigurator - Line 49



for (IDirectAction directAction : actionApiConfiguration.getListActions()) {
Class<?> actionClass = directAction.getClass();
final DirectAction directActionAnnotation = (DirectAction)actionClass.getAnnotation(DirectAction.class);

String actionName = actionClass.getSimpleName();
if (directActionAnnotation.action() != null && !directActionAnnotation.action().equals("")) {
actionName = directActionAnnotation.action();
}

RegisteredAction action = api.addAction(actionClass, actionName);
ActionScanner.scanAndRegisterAllKindsOfMethods(registry, api, action);
}


Well thats all!... Thanks for your contribution!.
Bye!.

pagullo
15 Sep 2009, 11:08 PM
It's done :)


Vincent,

First of all, congratulations for the nice work :).

...

I am attaching the changes I would like to commit into DirectJNgine in the src.zip file, and some little changes needed in your files to make them work with DJN in the spring_src.zip file. Look for 'PAGULLO' in source files to find the changes.

Main changes I propose to your files are:

- SpringRegistryConfigurator.java: I have made it use Scanner, so we do not risk introducing subtle bugs. In fact, the last post by mauro_monti mentions a problem processing annotations that should dissapear if we use Scanner.

- I think the ActionScanner.java file is not needed anymore.

- SpringDirectJNgineServlet.java: little changes to avoid having to add a doBeforeDjn initialization method in the base servlet. I am trying really hard to introduce as little changes as possible -I know, I'm *really* picky :">.


With respect to the global configuration, I feel uneasy too, but can't think of a better way than yours.

Now, let me confess that I haven't configured Spring to run the tests, only what's needed to compile: not too much free time nowadays. I think everything will work, but I'm looking forward for feedback from you.

...

Finally, I want to ask you to support using the default configuration, using web.xml, if only to be able to run all the automated tests to ensure we are not breaking things inadvertently. It should be as easy as writing a pair of additional lines to invoke the default processing...

Additionally, you might want to configure things in Spring so that you can run all automated tests to make sure everything works ok with your extensions. I always run all tests against the latest versions of Firefox, Chrome, IE and Safari before submitting a new release.

...

Again, congratulations :).

Regards

pagullo
15 Sep 2009, 11:11 PM
Yup!

Here are the files...

J@y
15 Sep 2009, 11:48 PM
One question, can I separate/allocate different remoting provider for batch ajax request?

Currently we use:
Ext.app.REMOTING_API.enableBuffer = 0;
var remotingProvider = Ext.Direct.addProvider(Ext.app.REMOTING_API);


is there a way to assign more than one remotingProvider to the Ext.Direct?

pagullo
16 Sep 2009, 2:48 AM
Vincent,

I made a mistake in the version of Scanner.java I sent you:

The correct code is:


private void scanAndRegisterActionClass(RegisteredAction action) {
assert action != null;
// ...
instead of current one:


private void scanAndRegisterActionClass(RegisteredAction action) {
assert action != null;
assert !this.registry.hasAction(action.getName()); // REMOVE THIS LINE
// ...


My apologies

pagullo
16 Sep 2009, 4:45 AM
One question, can I separate/allocate different remoting provider for batch ajax request?

Currently we use:
Ext.app.REMOTING_API.enableBuffer = 0;
var remotingProvider = Ext.Direct.addProvider(Ext.app.REMOTING_API);


is there a way to assign more than one remotingProvider to the Ext.Direct?

Jay,

Unfortunately, what you need to do is register the same Java class with two different action names, because there is no way you can use the same action name in two different providers at the same time *even* if they define different namespaces.

This is due to the low level protocol used by ExtJs Direct, not related to DJN itself.

There is a 'workaround': create different ExtJs actions for the same Java class for batched and non-batched work, as in


MyAction.myMethod(...); // Invoke MyJavaClass.myMethod
MyActionBatched.myMethod( ... ); // Invoke MyJavaClass.myMethod too! I think there is a way: use the new programmatic API in the 1.1 alpha 1 release to register a new DirectJNgine api that will be used to create the 'alternative' provider.

You can do this by getting the default RegisteredApi DJN will have created for you, and copying the existing actions to a new RegisteredApi, but with a different name.

Take a look at the manual/example for further info: it sounds like low level stuff, but once you take a look at the example you'll see that it is really easy.

...

As an aside, why do you need some things to be batched and others not? I'm really curious about the use case

J@y
16 Sep 2009, 7:53 PM
Thanks pagullo again,

In one of my panel, it contains several portlets (panel), each panel owns a dataview and store. That means 10 panels will make 10 AJAX requests to the server.

I'd want to separate these 10 requests into 2 groups, as a result each group has 5 requests.

Why I'm doing that?
If I make 10 requests into 1 batch (by setting the buffer size of remotingProvider), all the portlet's results will be held until all 10 requests got the response from server.

However, I don't want to set the buffersize to 0, which means 10 request will consume 10 individual AJAX requests. It waste a lot of bandwidth (the http header part).

So this is our scenario.

pagullo
17 Sep 2009, 3:25 AM
I think I get the point...

It would be nice if Extjs allowed us to specify the maximum batch size. Maybe you should request this feature to the ExtJs guys.

And, you might implement some "delay" feature that makes sure not too many requests are batched.

...

Now, if only DirectJNgine were capable of returning whatever individual requests it has finished handling after a "prudential time", returning a batch in several parts...

Maybe when I have more free time: it is not trivial because of multithreaded batched request handling. If somebody is willing to volunteer, I might help with this, though.

...

As an aside...

I think that sometimes batching per-se is not the problem, but mixing potentially slow methods with fast methods in the same batch is.

Being that the case, it might make a lot of sense to separate the slow methods in a different Java classes, and register it in a different api => you can use a non-batching provider for slow mehtods.

Not that this is very elegant, but it might work.

Regards

vlagorce
17 Sep 2009, 3:31 AM
Hi Djn people ;)

==================
@mauro_monti




[...]
I get an IOException saying \dst\Api-debug.js' exists but is a directory...
Do you know how to solve this problem?...
[...]

Strange exception.. The spring code just append text. It did not try to create file..
In debug mode did you find witch line of code throw it ?



[...]
On the other hand, i watched the class SpringRegistryConfiguration. Seems that registry actions, obviating the action paramete of the annotated class. Here is my contribution:

SpringRegistryConfigurator - Line 49 [...]

.

Thank you ;) And as Pedro say it's better to reuse the scanner to register actions.

==================
@pagullo


Vincent,

[...]

I am attaching the changes I would like to commit into DirectJNgine in the src.zip file, and some little changes needed in your files to make them work with DJN in the spring_src.zip file. Look for 'PAGULLO' in source files to find the changes.

Main changes I propose to your files are:

- SpringRegistryConfigurator.java: I have made it use Scanner, so we do not risk introducing subtle bugs. In fact, the last post by mauro_monti mentions a problem processing annotations that should dissapear if we use Scanner.

- I think the ActionScanner.java file is not needed anymore.


You'r right, I have also made this modification but don't send it :p.
The only modification need in Scanner could be the retrieves of the annotation. I'm not sure it's interesting..



- SpringDirectJNgineServlet.java: little changes to avoid having to add a doBeforeDjn initialization method in the base servlet. I am trying really hard to introduce as little changes as possible -I know, I'm *really* picky :">.


No no.. the less change they have the best it will for everybody ;) I will check it.




With respect to the global configuration, I feel uneasy too, but can't think of a better way than yours.

Now, let me confess that I haven't configured Spring to run the tests, only what's needed to compile: not too much free time nowadays. I think everything will work, but I'm looking forward for feedback from you.

...


I have not too much time too. I must find time in my working time :( May be in the middle of the next week.



Finally, I want to ask you to support using the default configuration, using web.xml, if only to be able to run all the automated tests to ensure we are not breaking things inadvertently. It should be as easy as writing a pair of additional lines to invoke the default processing...

Additionally, you might want to configure things in Spring so that you can run all automated tests to make sure everything works ok with your extensions. I always run all tests against the latest versions of Firefox, Chrome, IE and Safari before submitting a new release.

...

Again, congratulations :).

Regards

I will do that as soon as possible !




[..]


private void scanAndRegisterActionClass(RegisteredAction action) {
assert action != null;
assert !this.registry.hasAction(action.getName()); // REMOVE THIS LINE
// ...
My apologies

ok !


==================
@ ALL

I have made some change in springConfiguration I will send it after making test for pagullo.

Stsalomon90
24 Sep 2009, 2:53 PM
Greetings,

I have read the user manual and setup directjngine-1.0 in my web app. I am trying to load data into a grid using the DirectStore. DirectStore is succesfully querying the server but the returned result is not making it into my grid. It appears the loadRecords function is being passed false for the success parameter. Any idea what is going on here?



var memoryRecord = Ext.data.Record.create([{
name: 'name',
type: 'string',
allowBlank: false
},{
name: 'status',
type: 'int',
allowBlank: false
},{
name: 'nonHeapUsed',
type: 'float',
allowBlank: false
},{
name: 'heapUsed',
type: 'float',
allowBlank: false
},{
name: 'heapMax',
type: 'float',
allowBlank: false
}, {
name: 'nonHeapMax',
type: 'float',
allowBlank: false
}]);

Ext.Direct.addProvider(
Ext.app.REMOTING_API
);


var memoryStatsStore = new Ext.data.DirectStore({
paramsAsHash: false,
root: 'result',
directFn: FrameworkMemoryBean.loadFrameworkMemoryInfo,
idProperty: 'name',
fields: memoryRecord,
});

memoryStatsStore.load();

Response:

{"result":[{"heapMax":6144.0,"heapUsed":1626.252784729004,"nonHeapMax":-1.0,"nonHeapUsed":524.9034423828125,"name":"localhost","status":0}],"tid":2,"action":"FrameworkMemoryBean","method":"loadFrameworkMemoryInfo","type":"rpc"}

pagullo
27 Sep 2009, 11:12 PM
Hi

We need the Java code to get the whole picture.

That said, take an in-depth look at the code in DirectStore.java and how it is used in djn-tests.js. DirectStores have been fully tested in DJN, and so far they have worked without a problem.

Copy a working example/test code, make sure it works in your program, and then modify it moving towards your desired code. All too often I make little mistakes that are not easy to catch due to Javascript being way too tolerant: going step by step is a must in those cases.

Hope this helps

pagullo
28 Sep 2009, 12:14 AM
Hi

That said, take an in-depth look at the code in DirectStore.java ...

Gotcha!

The right file name is DirectStoreTest.java.

SreevaniN
5 Oct 2009, 4:24 AM
Hi Pedro,

I am planning to use the directjngine stack to help my project which involves calling crossdomain URLs. I must admit that I am still a beginner.

My hello message in my javascript file is coming up, which says that my EXtjs is configured properly.

I have followed the userguide to create a new web app. Now I have created my own class just like you have given and run my application. The Api.js is not getting created automatically. It does not seem to recognize my class!:s

I will be obliged with any help.

Thanks,
Sreevani



Oops. Yes, those using JDKs older than 1.5 are stuck.
We need to address this issue.

I don't like much adding preprocessing steps to compilation, and I think that will be a must with the Apache Commons Attributes (http://commons.apache.org/attributes/) library -haven't used it though, maybe there are alternatives...

Anyway, DirectJNgine annotations are really simple, and we can do without their parameters 99% of the time. I don't think I will add complex annotations later. No need for a full fledged substitute for 1.5 annotations.

So, what about using a naming convention instead?

- Methods starting with "djn_" will be considered as annotated with @DirectMethod
For "djn_xyz" the method name will be "xyz."

- Those starting with "djnform_" will be considered as a form post method (@DirectPostMethod).
For "djnform_xyz" the method name will be "xyz."

- Those starting with "djnpoll_" will be considered as @DirectPollMethod.
For "djnpoll_xyz", the event name will be "xyz".


This solution is simple, easy to understand and easy to implement. I think this solves the issue.

If it is acceptable to everybody, I will consider it for inclusion in the next public release (0.7.3, due on Wednesday 15).

What do you think?

Regards,

Pedro Agullo

pagullo
5 Oct 2009, 8:46 AM
If you are having trouble, maybe the easiest way to make sure things will work is to use the example application to start your own app.
Just make sure you can make it work to begin with, add your own "hello world" example and then remove all unneeded functionality.

If, after trying this, things do not work, post the web.xml and your class source code.

By the way, I assume you are using JDK 1.5, right? I decided not to support earlier earlier JDKs: you can find the reason somewhere else in this thread.

minneyar
14 Oct 2009, 10:40 AM
This may be a silly question, but is batching supposed to work when polling multiple providers?

That is, let's say I set up a couple of different providers like so:

Ext.Direct.addProvider({
type: 'polling',
url: Ext.app.POLLING_URLS.firstMethod
});
Ext.Direct.addProvider({
type: 'polling',
url: Ext.app.POLLING_URLS.secondMethod
});
Ext.Direct.on('firstMethod', function(result) {});
Ext.Direct.on('secondMethod', function(result) {});


When watching the console log in Firebug, I see queries going to both provider URLs at the same time. As far as I can tell, I have DirectJNgine set up properly and everything else is working fine. I had expected that those calls would be batched together. Is there something that I'm missing?

I've got a web page that's currently doing a lot of polling via old-fashioned timers and AJAX calls, and I was hoping that this would make that process a lot nicer. I suppose I could just replace the AJAX calls with functions that call a remoting provider and keep the timers, but it seems like the polling providers should be able to replace that altogether...

minneyar
14 Oct 2009, 12:15 PM
Here's another question, this one might be tricky...

In a servlet, is there any way to get access to the HttpServletRequest that lead to that method call? I ask because I'm running Tomcat on a servet with multiple network interfaces, and I have a servlet that needs to, at runtime, determine which interface requests to Tomcat are arriving on and then use that same interface to query another server and return its status. Currently I can just call "getLocalAddr" on the HttpServletRequest to get the interface I need, but I don't see any way to do that in a method that was annotated with @DirectMethod.

vlagorce
15 Oct 2009, 4:56 AM
No idea for the first question..sorry


[...] is there any way to get access to the HttpServletRequest [...] in a method that was annotated with @DirectMethod.[...]

You can't access the request when you are in a directAction. You need to override the DirectJNgineServlet and find a way to give the request or just the LocalAddr to the called method.(I didn't have the source I can't help you any more...)

Someone needed to access the request to keep object in session. You will found the workaround here.. https://www.extjs.com/forum/showthread.php?p=368005 .

pagullo
15 Oct 2009, 5:46 AM
This may be a silly question, but is batching supposed to work when polling multiple providers?

That is, let's say I set up a couple of different providers like so:

Ext.Direct.addProvider({
type: 'polling',
url: Ext.app.POLLING_URLS.firstMethod
});
Ext.Direct.addProvider({
type: 'polling',
url: Ext.app.POLLING_URLS.secondMethod
});
Ext.Direct.on('firstMethod', function(result) {});
Ext.Direct.on('secondMethod', function(result) {});
When watching the console log in Firebug, I see queries going to both provider URLs at the same time. As far as I can tell, I have DirectJNgine set up properly and everything else is working fine. I had expected that those calls would be batched together. Is there something that I'm missing?

I've got a web page that's currently doing a lot of polling via old-fashioned timers and AJAX calls, and I was hoping that this would make that process a lot nicer. I suppose I could just replace the AJAX calls with functions that call a remoting provider and keep the timers, but it seems like the polling providers should be able to replace that altogether...

As far as I know, the provider is the "batching unit" for Ext.Direct, so I would not expect poll calls from different providers to be batched :(.

You might want to consider consolidating several poll calls into a single call that returns the aggregated results of all of them -depending on your scenario.

Regards,

minneyar
15 Oct 2009, 7:00 AM
Someone needed to access the request to keep object in session. You will found the workaround here.. https://www.extjs.com/forum/showthread.php?p=368005 .

Ah, using a filter to catch the interface address is a great idea. That's a lot cleaner than the previous way I was doing it, too. Thanks!

It's too bad you can't batch calls to different providers, but that makes sense... I'll probably consolidate a few of them and just have the less frequent, higher bandwidth calls use a remoting provider.

pagullo
16 Oct 2009, 1:11 AM
We have released DirectJNgine 1.1 final today, wich includes support for programmatic API definition and better support for developing your own DirectJNgineServlet based custom servlets.

Support for programmatic API definition
Now it is possible to define the API programmatically, making it possible to bypass the way methods and actions are registered by DirectJNgine.

This makes it possible, for example, to generate an Ext.Direct API for Java classes generated on the fly, etc.

See chapter 12 in the User's Guide for an explanation and examples.

Creating custom servlets that extend DirectJNgine is now much easier
The DirectjNgineServlet class has been modified to make it much more extensible: as a result, third parties are now able to provide extensions such as support for Spring, etc.

Regards,

minneyar
16 Oct 2009, 5:36 AM
We have released DirectJNgine 1.1 final today, wich includes support for programmatic API definition and better support for developing your own DirectJNgineServlet based custom servlets.

Very nice, right after I started working with 1.0. ;-)

However, I've noticed that the license between 1.0 and 1.1 seems to have changed from the LGPLv3 to GPLv3. I'm working on a commercial project, and we're ok with LGPL libraries, but we can't use GPL ones, except in cases where we can obtain a commercial license for it (such as ExtJS). In the readme file, when it says "Commercial use is permitted to the extent that the code/component(s) do NOT become part of another Open Source or Commercial developed licensed development library or toolkit without explicit permission," is that meant to be an exception to the standard terms of the GPL? If so, what motivated your change from LGPL to GPL?

GregT
16 Oct 2009, 12:20 PM
Hi Pedro,

I hope I now have found the correct thread for a DJN question?

In the Ext documentation for JsonReader, it describes using the metaData property and I was wondering how one would go about that when the JSON comes from DJN.

I think maybe I need to write my own Serializer. Is that correct?

Does this whole idea of using metaData with DJN's JSON, basically to avoid a bunch of extra JsonReaders and redundant definition of field lists, sound reasonable?

Thank you and best regards.

pagullo
17 Oct 2009, 2:07 AM
Very nice, right after I started working with 1.0. ;-)

However, I've noticed that the license between 1.0 and 1.1 seems to have changed from the LGPLv3 to GPLv3. I'm working on a commercial project, and we're ok with LGPL libraries, but we can't use GPL ones, except in cases where we can obtain a commercial license for it (such as ExtJS). In the readme file, when it says "Commercial use is permitted to the extent that the code/component(s) do NOT become part of another Open Source or Commercial developed licensed development library or toolkit without explicit permission," is that meant to be an exception to the standard terms of the GPL? If so, what motivated your change from LGPL to GPL?

The 'reason' to change licensing is called 'failure chaining' + 'basic lack of interest on legalese' :">

Somebody else found an inconsistency with my licensing (DirectJNgine website + license text file saying one thing, my source files a different one), and I rushed to 'solve' it without re-checking my facts (hate wading into 'legalese'), so I just merrily changed it to GPL :(. As easy as that...Sigh.

...

Time to recheck things and ask you guys for help...

What do I want from my license?

- I would like as much people as possible to use DirectJNgine, including commercial projects.
- I would like to get credit for the effort of making DirectJNgine.
- I don't want Mr. Smart to change 'the color of the User's Guide font' or add a pair of classes to the library and claim DirectJNgine as his work or to have made a substantial addition. And I don't want him to add it to a library that might 'swallow' DJN. But I would love people to build libraries or tools on top of DJN.

The



"Commercial use is permitted to the extent that the code/component(s) do NOT become part of another Open Source or Commercial developed licensed development library or toolkit without explicit permission,"
text was added just to make sure the third scenario does not happen. I found it in somebody else's source code and it seemed to fit with what I wanted + I liked the wording -now, I hope he does not sue me for some unknown reason, ha ha ;).

Now, if somebody finds that LGPL v3 + 'the custom text' is not adequate to get what I want, I will be happy if he comments, I fix things, and we all come back to writing code, which is what I enjoy, and the reason to write and document DJN and give it for free :).

So if nobody finds some problem with what I want and the licensing, I will publish DJN as LGPL v3 adding that custom text.

Comments, anyone?

pagullo
17 Oct 2009, 2:35 AM
Hi Pedro,

I hope I now have found the correct thread for a DJN question?

In the Ext documentation for JsonReader, it describes using the metaData property and I was wondering how one would go about that when the JSON comes from DJN.

I think maybe I need to write my own Serializer. Is that correct?

Does this whole idea of using metaData with DJN's JSON, basically to avoid a bunch of extra JsonReaders and redundant definition of field lists, sound reasonable?

Thank you and best regards.

I haven't ever used metaData, so it is very likely that I might be missing some important information.

That said, it seems as if defining a MetaData class with the fields shown for the 'metaData' field in the documentation, and adding it to the returned data should be easy. I do not think you need to get into custom JSON serialization.

The automated tests included with DirectJNgine show how to define and return really complex data structures (object having other object that contains list of object, etc.): maybe you will want to take a look at how they are handled. Just look at the Java and the Javascript side at the same time to make sense of it all.

If things do not work, just send us the Java class defining the data to return + the code returning and maybe some of us will be able to help you.

Regards

dionisexorcius
19 Oct 2009, 7:11 AM
Hello,

I am interested could this solution be used to invoke Java services from within AIR applications developed with ExtJs?

Best regards!

GregT
22 Oct 2009, 9:39 AM
Hi Pedro,

Now I need to figure out how to pass a set of record-like structures *to* DJN, as opposed to getting Lists of Objects out of DJN. The latter is well documented but I don't see anything about the former. I assume this will involve Ext.Encode and probably some JSON parsing and object deserialization on the server (things I know nothing about). Before I flail around for hours, do you have any general guidance?

Also, regarding Metadata and your earlier reply. Thank you for the reply. I think just creating a Metadata class would work but it implies duplicating the class definitions in this class in some form (and having to update it every time you add a new class etc.).

Perhaps a better solution would be modifying DJN to create the Metadata by reflectively looking at the thing it is serializing. This would be a big plus for me so I am going to research this next week. If you think I am totally off track, please let me know.

Cheers,
Greg

pagullo
22 Oct 2009, 10:43 PM
Greg,

Take a look at the VeryComplexObject class and how it is defined/used in the automated DJN tests.

If you want to pass a list of complex objects, it should be as easy as passing them as List<MyComplexObject> or MyComplexObject[] to the Java code.

...

Your approach to the metadata thing seems to be right. That said, I consider this functionality can and should be built on top of DJN, without modifying it.

As I see it, you need to create a method that scans a Java class and returns the corresponding Metadata object, which should be defined to perfectly map the Javascript object representing the metadata: I think your Java methods should return this (and additional data) without any special processing, as we do with any other Java object/s. Of course, until you give it a try, we will not know -but I bet it is possible.

Will be nice if you keep us up to date on your attempts.

GregT
23 Oct 2009, 4:44 AM
Pedro,

In this code from djn-tests.js, what does the 'null' mean? How does DJN know whether to deserialize a particular collection as a List vs. an Array (or for that matter some other Java collection type?) In terms of JSON representation surely they are identical, so some special 'collection type indicator' must be necessary?

Thank you,
Greg

test_serverReceivingVeryComplexObject: function(){
var obj = {
ints: [33, null],
myComplexObject: {
name: 'MyPet',
age: undefined // We expect 'undefined' to be ignored!
},
moreComplexObjects: [null, {
name: null,
age: 5
}]
};
ServerMethodParametersReceptionTest.test_serverReceivingVeryComplexObject(obj, function(provider, response){
Djn.Test.checkSuccessfulResponse("test_serverReceivingVeryComplexObject", response, response.result);
});
},

pagullo
23 Oct 2009, 5:19 AM
1) What does 'null' mean?

Well, I was just testing that null data was handled correctly, nothing else. What it means or whether it makes sense will depend on your context. Up to you.

2) Decoding from JSON data to Java is handled by the GSON library: you should go there for specific details.

Now, how does gson know whether it needs to create an array or a list? I just use introspection to check what the Java method expects, and tell it to gson...

Of course, not all collections can be handled correctly (what the hell should you instantiate for a parameters with a 'Collection' type?). But, generally speaking, sticking to lists or arrays always works.

If you want my advice, just try to write the Java code you want, and you will quickly find out what works and what does not when it comes to collection handling.

kschlaudt
3 Nov 2009, 10:03 AM
Hi Pedro & Vincent,

I really appreciate both of your efforts integrating Spring, DJN & ExtJS.

However, still find myself a little overwhelmed with all of the configurations.

Do either of you have a complete working example you can share?

Thanks again!

Kurt

vlagorce
3 Nov 2009, 11:02 PM
Hi Pedro & Vincent,

I really appreciate both of your efforts integrating Spring, DJN & ExtJS.

However, still find myself a little overwhelmed with all of the configurations.

Do either of you have a complete working example you can share?

Thanks again!

Kurt


Hi,
I have almost finished to release the spring-api but I didn't find the time to release and write the documentation.

I give you the last release candidate and the source of my test project !

You will find example about how to declare action and js-Api in the spring-definition.xml.

There is 4 method to do it.

-The first is className injection. Used to run the base test of Djn without coding.

-The second is a simple injection. Action is declared as a bean and injected in the ApiConfiguration. (not implemented in this version)

-The third method is autowired method.

Action could be declared in context or scanned by spring (@Component). Action must inherit the interface used in the ApiConfiguration.

Hope to help you.
I aim to release before the end of the next week..Don't hesitate to give your opinion about this api :)


Vincent

clynnh
9 Nov 2009, 2:16 PM
Hi Pedro!

Thanks for this great framework. I downloaded the code today and have run into a roadblock. I run the test application but I can't get access to the HttpSession or HttpServletRequest objects when I am in the class Profile and calling the method updateBasicInfo. Typically i have access to the session through my JSF faces context.

Any help would be greatly appreciated.

Thanks again,

ClynnH

Whatty
9 Nov 2009, 3:48 PM
Good afternoon,

We are integrating ExtJS with the Spring framework (IoC / DI container). The Spring framework manages our beans and the relationships between them and all requests for existing or new beans should go through this framework. This requires the HTTP session which is where the current context is maintained across requests.

Thus in particular need to put the following code in the Servlet which serves up the DirectJngine requests.



ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());

context.getBean("loginBean");
Once we have the application context we can dispatch the servicing of the ExtJS requests to the bean returned from the application context.

What is the best way to accomplish this in a nice manner (i.e. not having to change your code base)

I am assuming in the servlet that you are executing some sort of newInstance() call against that class and then dispatching the method to the newly created object.

It would be nice to have a context based bean factory that gives us the bean to service the ExtJS request that was configurable through the web.xml, but I have not yet looked at the code for the DirectJngine to see how easily that would be accomplished.

Any suggestions would be greatly appreciated.

On a side note we are doing something very similar on the .NET side and are mostly likely going to have a similar type of implementation.

Thanks in advance.

Whatty

PS: I just read the post above mine and realized that this is already in the works. Cool! How far along is this and is any help needed?

PPS: Is the same thing occurring for the .NET frameworks

Whatty
9 Nov 2009, 4:01 PM
There wouldn't happen to be a sample application that works with the Spring integration?

pagullo
10 Nov 2009, 11:16 PM
Hi Pedro!

Thanks for this great framework. I downloaded the code today and have run into a roadblock. I run the test application but I can't get access to the HttpSession or HttpServletRequest objects when I am in the class Profile and calling the method updateBasicInfo. Typically i have access to the session through my JSF faces context.

Any help would be greatly appreciated.

Thanks again,

ClynnH

Thanks.

You can implement a servlet filter that stores the http-session or http servlet request in a thread-local variable so that you can get access to them later.

This issue has been discussed before in this thread, take a look at some of the posts in http://www.extjs.com/forum/showthread.php?p=368005, for example.

Best regards

mbarto
12 Nov 2009, 8:21 AM
I would like to suggest a little fix to the Api code generation. The current version generates a wrong BASE_URL if the web page is on the root folder (ex. http://localhost:8080/index.jsp).

I would change the current implementation of appendJsExpressionToGetBaseUrl with:


private void appendJsExpressionToGetBaseUrl(StringBuilder result) {
assert result != null;

result.append( "window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/').length>2 ? window.location.pathname.split('/')[1]+ '/' : '') + " );
}

Whatty
12 Nov 2009, 11:04 AM
Does djn provide any approach to get HttpServletRequest and HttpSession object?

Given this and the response, then what is Directjngine approach to session management in a multi-user web application.

As a Java / JSF developer a lot of the session management details are managed by JSF and the developer is not exposed to the details they just have access to the session object if needed.

It is extremely important that this engine supports multiple simultaneous requests to different user sessions, encapsulating the logical boundaries between the multiple user sessions, otherwise I am having a hard time understanding the applicability of Directjngine

Excuse me if I am missing something on this but we are trying to integrate this at the very moment and are struggling with how to maintain session state for a particular user session.

Whatty

J@y
12 Nov 2009, 10:52 PM
Given this and the response, then what is Directjngine approach to session management in a multi-user web application.

As a Java / JSF developer a lot of the session management details are managed by JSF and the developer is not exposed to the details they just have access to the session object if needed.

It is extremely important that this engine supports multiple simultaneous requests to different user sessions, encapsulating the logical boundaries between the multiple user sessions, otherwise I am having a hard time understanding the applicability of Directjngine

Excuse me if I am missing something on this but we are trying to integrate this at the very moment and are struggling with how to maintain session state for a particular user session.

Whatty

I face the same problem too...

Even I can pass the session object to the server side by the server filter, it is impossible to handle all the requests and redirect them to different pages.

DWR supports the httpservlet, this is the main reason y most of the ppl still stick to it.

pagullo
12 Nov 2009, 11:17 PM
I would like to suggest a little fix to the Api code generation. The current version generates a wrong BASE_URL if the web page is on the root folder (ex. http://localhost:8080/index.jsp).

I would change the current implementation of appendJsExpressionToGetBaseUrl with:


private void appendJsExpressionToGetBaseUrl(StringBuilder result) {
assert result != null;

result.append( "window.location.protocol + '//' + window.location.host + '/' + (window.location.pathname.split('/').length>2 ? window.location.pathname.split('/')[1]+ '/' : '') + " );
}



Good one!

I will fix it as soon as possible.

Best regards

pagullo
13 Nov 2009, 1:25 AM
Given this and the response, then what is Directjngine approach to session management in a multi-user web application.

As a Java / JSF developer a lot of the session management details are managed by JSF and the developer is not exposed to the details they just have access to the session object if needed.

It is extremely important that this engine supports multiple simultaneous requests to different user sessions, encapsulating the logical boundaries between the multiple user sessions, otherwise I am having a hard time understanding the applicability of Directjngine

Excuse me if I am missing something on this but we are trying to integrate this at the very moment and are struggling with how to maintain session state for a particular user session.

Whatty


No, you are not missing something. And yes, I agree: state management is very, very important.

Now, I think there is an expectations mismatch.

DirectJNgine is *not* competing against JSF or other frameworks/libraries. DJN is just a Java implementation of the Ext.Direct communication protocol, nothing more.

If you were using ExtJs + Java before, it will probably make your life much easier. If you were not, you willl need to check whether ExtJs + Java will fit the bill. When evaluating this, you should take what DJN provides into account.

ExtJs does not attempt to solve all problems of web development, including that of state management. ExtJs is all about providing an amazingly rich client side UI, and in that respect I think it is unsurpassed. But that power comes with a cost.

So, when it comes to the "what is the applicability of DJN?" question, I think you should change your question to "what is the the applicability of ExtJS?". If ExtJs is applicable, then DJN will certainly make your life easier.

...

Support for handling state management in a robust and performant way is one of those funny things I would love to implement. But this is a non-for-profit project, I have to make a living, and days have 24 hours -a constraining environment for innovation ;-).

I want to encourage the community to attempt to solve the problem of state management for ExtJs + DJN -and contribute their code back. Maybe you could give it a try :-).

Best regards

pagullo
13 Nov 2009, 1:54 AM
I face the same problem too...

Even I can pass the session object to the server side by the server filter, it is impossible to handle all the requests and redirect them to different pages.

DWR supports the httpservlet, this is the main reason y most of the ppl still stick to it.

Jay,

Do you just need access to



HttpServletRequest
HttpServletResponse
HttpSession
ServletContext
ServletConfig?


I am not familiar with DWR, but so far what I've seen it provides when it comes to servlet support is just this -as seen in http://directwebremoting.org/dwr/server/javaapi.html. Can you provide me with links to that functionality you are missing?

While I do not plan on undertaking support for complex state handling (or rather what I consider to be "complex state handling"), providing support for this is so easy I might implement it if you guys are really interested in it.

What else is there in DWR that you are missing in DJN? Code is what I need, can you provide me with code samples for those things you are doing with DWR now that you can't do with DJN?

I need you guys to go down to details if I am to consider additions/modifications.

Best regards,

Whatty
13 Nov 2009, 6:08 AM
Jay,

Do you just need access to



HttpServletRequest
HttpServletResponse
HttpSession
ServletContext
ServletConfig?


I am not familiar with DWR, but so far what I've seen it provides when it comes to servlet support is just this -as seen in http://directwebremoting.org/dwr/server/javaapi.html. Can you provide me with links to that functionality you are missing?

While I do not plan on undertaking support for complex state handling (or rather what I consider to be "complex state handling"), providing support for this is so easy I might implement it if you guys are really interested in it.

What else is there in DWR that you are missing in DJN? Code is what I need, can you provide me with code samples for those things you are doing with DWR now that you can't do with DJN?

I need you guys to go down to details if I am to consider additions/modifications.

Best regards,


I fully understand what you are saying when it comes to complex session management, but having some sort of solution for session management is paramount to be able to use this framework in the context of a multi-user web application.

We are currently investigating (today) the Spring / DirectJngine integration and am hoping that this provides a solution for our problem.

Having said this we have yet to investigate the in & outs of session management in a Java based web application (which I would agree is probably a big undertaking and complex), but I am going to assume that either the JSP or JSF frameworks have integration hooks for this beyond the servlet filter option.

Maybe another approach to the same question would be easier. How in your opinion was this going to support a multi-user web application. In particular, how would I be able to access user state stored on the server. Unless you are taking a sometimes touted Microsoft approach where everything is stateless, you must be able to access the session somehow.

Whatty

pagullo
16 Nov 2009, 4:38 AM
I fully understand what you are saying when it comes to complex session management, but having some sort of solution for session management is paramount to be able to use this framework in the context of a multi-user web application.

We are currently investigating (today) the Spring / DirectJngine integration and am hoping that this provides a solution for our problem.

Having said this we have yet to investigate the in & outs of session management in a Java based web application (which I would agree is probably a big undertaking and complex), but I am going to assume that either the JSP or JSF frameworks have integration hooks for this beyond the servlet filter option.

Maybe another approach to the same question would be easier. How in your opinion was this going to support a multi-user web application. In particular, how would I be able to access user state stored on the server. Unless you are taking a sometimes touted Microsoft approach where everything is stateless, you must be able to access the session somehow.

Whatty

Of course, I'm not advocating a "100% stateless" approach, and this means in practice that you probably have to use the HttpSession in one way or other -whether you do it directly or your library/framewok does it for you under the covers.

The filter technique discussed elsewhere is intended to give you access to HttpSession, ServletContext, ServletRequest and ServletResponse from your DJN methods, so that you can manage state on your own -just that.

Very raw, but useful and workable. When I have implemented it, it has worked with no problem at all.

Why is such approach *not* a part of DJN right now?

1) I wanted to avoid people thinking this is *The Right And Only Way* with DJN.

And, in fact, I have thought of a much more advanced state management solution, to be built on top of DJN, rather than as part of it. No time/financing for that, though -so,just a dream.

2) I think state management and communication should be orthogonal.

DJN is an implementation of a communication protocol, Ext.Direct. I wanted DJN to remain blissfully unaware of sessions and the like, as state managment is a different concern.

3) I felt writing such a filter was so easy that DJN users would write their own as needed.

If you take a look at the code below, you will see that it is rather short.

Nowadays, due to popular demand, I'm leaning towards providing and out of the box implementation of such a mechanism for the next DJN version. But before I do, I would like to get feedback on this issue from as many real DJN users as possible.

Here is the source code for a "just in an hour" filter + WebContext class that makes sessions etc. available to DJN methods + a simple test DJN method. Maybe this code might be the basis for the desired functionality. (Note: this might not work with multithreaded request handling for batched request, so just disable it)


Filter
====


package com.softwarementors.extjs.djn.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.NDC;

public class DirectJNgineFilter implements Filter {

private ServletContext servletContext;

public void destroy() {
// Do nothing
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
boolean initializeContext =
request instanceof HttpServletRequest && response instanceof HttpServletResponse;
WebContext context = null;
if( initializeContext ) {
context = WebContext.initializeWebContext( (HttpServletRequest)request,
(HttpServletResponse)response, this.servletContext);
NDC.push( "session=" + ((HttpServletRequest)request).getSession().getId() );
}

chain.doFilter(request, response);

if(initializeContext) {
assert context != null;
NDC.pop();
context.close();
}
}

public void init(FilterConfig config) throws ServletException {
this.servletContext = config.getServletContext();
}

}
Class giving access to HttpSession, etc. from a DJN method
=============================================


package com.softwarementors.extjs.djn.servlet;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class WebContext {
private static ThreadLocal<WebContext> webContext =
new ThreadLocal<WebContext>();
private HttpServletRequest request;
private HttpServletResponse response;
private ServletContext servletContext;
private boolean initialized;

private WebContext( HttpServletRequest request, HttpServletResponse response,
ServletContext servletContext )
{
assert request != null;
assert response != null;
assert servletContext != null;

this.request = request;
this.response = response;
this.servletContext = servletContext;
this.initialized = true;
}

public static WebContext get() {
assert isWebContextInitialized();

return webContext.get();
}

/* package */ static WebContext initializeWebContext( HttpServletRequest request,
HttpServletResponse response, ServletContext servletContext)
{
assert request != null;
assert response != null;
assert servletContext != null;
assert !isWebContextInitialized();

WebContext result = new WebContext(request, response, servletContext );
webContext.set( result );
return result;
}

/* package */ void close() {
assert isWebContextInitialized();

// WebContext context = webContext.get();
this.request = null;
this.response = null;
this.servletContext = null;
this.initialized = false;
webContext.set(null);
}

/* package */ static boolean isWebContextInitialized() {
WebContext context = webContext.get();
return context != null;
}

public boolean isInitialized() {
return this.initialized;
}

public HttpServletRequest getRequest() {
assert isInitialized();

return this.request;
}

public HttpServletResponse getResponse() {
assert isInitialized();

return this.response;
}

public HttpSession getSession() {
assert isInitialized();

return this.request.getSession();
}

public ServletContext getServletContext() {
assert isInitialized();

return this.servletContext;
}
}

DJN method accessing session and other contextual info
=============================================


package com.softwarementors.extjs.djn.test.servlet;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

import com.softwarementors.extjs.djn.config.annotations.DirectMethod;
import com.softwarementors.extjs.djn.servlet.WebContext;

public class WebContextTest {
public static class WebContextInfo {
public int callsInSession = 0;
public int callsInApplication = 0;
public String sessionId;
}

@DirectMethod
public WebContextInfo test_webContext() {
WebContext context = WebContext.get();
HttpSession session = context.getSession();
ServletContext application = context.getServletContext();

// Keep a counter of how many times we have called this method in this session
Integer callsInSession = (Integer)session.getAttribute("callsInSession");
if( callsInSession == null ) {
callsInSession = new Integer(0);
}
callsInSession = new Integer(callsInSession.intValue() + 1);
session.setAttribute("callsInSession", callsInSession);

// Keep a counter of how many times we have called this method in this application
Integer callsInApplication = (Integer)application.getAttribute("callsInApplication");
if( callsInApplication == null ) {
callsInApplication = new Integer(0);
}
callsInApplication = new Integer(callsInApplication.intValue() + 1);
application.setAttribute("callsInApplication", callsInApplication);

// Return status information
WebContextInfo result = new WebContextInfo();
result.callsInApplication = callsInApplication.intValue();
result.callsInSession = callsInSession.intValue();
result.sessionId = context.getSession().getId();
return result;
}
}

Filter configuration in web.xml
======================


<filter>
<filter-name>djnFilter</filter-name>
<filter-class>com.softwarementors.extjs.djn.servlet.DirectJNgineFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>djnFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


@Whatty
Is the approach used by the enclosed code ok for you? If so, use the code and let us know how it goes. You can add it to the already existing demo app -remember to add the new test class to web.xml

@Jay and other DWR users
Still interested in taking a look at code illustrating what DWR is giving you that DJN does not.
I'm always interested in making DJN better, real code exemplifying real needs is what will provide fuel for it to move forward :).

@All
Now, I want to know whether people wants the "make HttpSession, etc. available to DJN methods" functionality included as part of DJN 1.2: just vote in this thread :)

Best regards,

Whatty
16 Nov 2009, 8:51 AM
Good morning,

We are working with the djn-spring integration with a fair amount of success.

Just wanted to confirm one item, our action classes that should be hooked up the djnEngine and ultimately have their API generated to the API.JS file need to implement the



IAutoWiredDirectAction interface


and in our SpringGlobalConfiguration configuration file, we use the following:



<bean id="autowiredActionApiConfiguration" class="com.extjs.djn.spring.test.autowired.api.AutowiredActionApiConfiguration">
<property name="apiName" value="PureFees-API" />
<property name="apiNamespace" value="Ext.app" />
<property name="apiFileName" value="PureFees-API.js" />
<property name="apiFolder" value="djn/api" />
</bean>


This works but is it the prescribed method for wiring up our Spring managed beans to the DJN API.

Additionally, is there any way to get the Spring integration to recognize that a class has one of the DJN annotations and automatically wire it up as opposed to having to implement the interface



IAutoWiredDirectAction


Thanks in advance.

Whatty

BTW, thanks for the effort to all in getting these two frameworks to work together.

J@y
16 Nov 2009, 7:07 PM
Jay,

Do you just need access to



HttpServletRequest
HttpServletResponse
HttpSession
ServletContext
ServletConfig?


I am not familiar with DWR, but so far what I've seen it provides when it comes to servlet support is just this -as seen in http://directwebremoting.org/dwr/server/javaapi.html. Can you provide me with links to that functionality you are missing?

While I do not plan on undertaking support for complex state handling (or rather what I consider to be "complex state handling"), providing support for this is so easy I might implement it if you guys are really interested in it.

What else is there in DWR that you are missing in DJN? Code is what I need, can you provide me with code samples for those things you are doing with DWR now that you can't do with DJN?

I need you guys to go down to details if I am to consider additions/modifications.

Best regards,

yes you are right, thats all about DWR, nothing more.

I know its a very simple task for you to enhance the DJN to support the above java objects, as I've also investigated the source code of DJN before.

Although the java servlet objects are not designated to be supported by DJN in its purpose, but this extra bonus supports will make everything becomes easy.

I'm happy to see that now DJN is going to support the basic session controls, deeply appreciated to your work! thanks!

mct
16 Nov 2009, 11:56 PM
I'm happy to see that now DJN is going to support the basic session controls.

+1

I'd like too.

Ramzi

vlagorce
17 Nov 2009, 1:37 AM
Good morning,

We are working with the djn-spring integration with a fair amount of success.

Just wanted to confirm one item, our action classes that should be hooked up the djnEngine and ultimately have their API generated to the API.JS file need to implement the



IAutoWiredDirectAction interface
and in our SpringGlobalConfiguration configuration file, we use the following:



<bean id="autowiredActionApiConfiguration" class="com.extjs.djn.spring.test.autowired.api.AutowiredActionApiConfiguration">
<property name="apiName" value="PureFees-API" />
<property name="apiNamespace" value="Ext.app" />
<property name="apiFileName" value="PureFees-API.js" />
<property name="apiFolder" value="djn/api" />
</bean>
This works but is it the prescribed method for wiring up our Spring managed beans to the DJN API.

Additionally, is there any way to get the Spring integration to recognize that a class has one of the DJN annotations and automatically wire it up as opposed to having to implement the interface



IAutoWiredDirectAction
Thanks in advance.

Whatty

BTW, thanks for the effort to all in getting these two frameworks to work together.

I think it's the best way to wiring up beans it doesn't need further declaration.

Spring autowiring features need to know the type or the name of the bean you want to be autowired.
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire

In Spring context bean's name is an unique value. The com.extjs.djn.spring.test.autowired.api.AutowiredActionApiConfiguration was created to define many action that's why I use the injection by type. Interface is the most useful type to do this.

In your project instead of using the test implementation of ActionApiConfiguration write your own with the common type of your action. I didn't implement the AutowiredActionApiConfiguration in the core API because each project may have its own action interface or abstract class...

If you have many action using different type you can also add an autowired setter with the corresponding type. But it's make no sense to have one setter per action...

I hope giving you a good explanation.

Do not hesitate to send me some modification requests or remarks :)

Whatty
17 Nov 2009, 6:19 AM
Thanks for the response.

Just a quick clarification, the "test.autowired" hierarchy was for your testing purposes and you did not include them in the base package since you expected people to have their own action hierarchy already in place.

Thus to include my action classes in the API generation I would do something like the following:



public class MyApiConfiguration extends BaseActionApiConfiguration<IMyDirectAction> {

@Autowired
@Override
public void setListActions(List<IMyDirectAction> listActions) {
super.setListActions(listActions);
}
}


and my action classes would only need to implement



IMyDirectAction


With the appropriate changes to my config

If I already happen to have a abstract class or interface in place (which I do) I would just change the MyApiConfiguration to use that interface / class instead.

Well done!

Have you been following the discussion's related to session management in the base jNgine. I know that Spring has a WEB framework and related web session management packages and was wondering if it would be possible to hook into Spring's WEB frameworks to assist with this session management, or would this unneccessarily tie the underlying jNgine to the SPRING framework (unless the web framework can be yanked out of the base SPRING framework)?

Thanks

Whatty

vlagorce
17 Nov 2009, 8:58 AM
[...]
Have you been following the discussion's related to session management in the base jNgine. I know that Spring has a WEB framework and related web session management packages and was wondering if it would be possible to hook into Spring's WEB frameworks to assist with this session management, or would this unneccessarily tie the underlying jNgine to the SPRING framework (unless the web framework can be yanked out of the base SPRING framework)?

[...]

Actually in my project we doesn't need to manage session but I understand your need and I'm quite sure I will need to have this feature... We use Ext-direct only for request like search,...

I'm not a great Spring-web user but for all I know I think Spring-web is not a solution.
It's a 'mvc' implementation for web application ''like'' Struts/JSF(?)/... there is now way to map Ext-direct request to 'spring/struts/..-action' through Djn!

What you need is to configure your web application framework (SpringWeb,JSF,..) to return json instead of html and to accept receiving JSON. But I'm not sure it's possible..

I didn't test but may be something is possible with restlet http://www.restlet.org/ but you will have to do some development (e.g. generate an API-js like Djn do with your restlet resources)... This framework accept a lot of input type and a lot of output type.. JSON is accepted in standard and it's allow to manage user session.

I have no time to search further workaround but what about the filter given by pedro ? It's not what you need ?

You have to keep in mind that
-Djn is not designed to be in front of, or behind, a Web application framework.

-Djn-Spring only allow to configure action without declaration in the web.xml (except servlet) and with the autowiring feature with a small number of bean declaration.
...

I think I will take a look at this issue but before I should release the djn-spring 1.1 :)


Regards,
Vincent
(I hope to be clear as you can read english is not my mother tong :p)

Whatty
17 Nov 2009, 9:04 AM
We are currently investigating the servlet approach that and I believe are making some progress, will let you know once we have something workable.

Thanks for the assistance

dreamtaotao
23 Nov 2009, 5:46 PM
I like DirectJNgine. I tried to DirectJNgine with struts2 integration but it seems impossible, it seems not work with MVC frameworks is that right? For example struts2. If you can do to give some clarification. Thank you, sorry my English not good

pagullo
23 Nov 2009, 11:15 PM
DirectJNgine is only integrated with the servlet API at this moment.

The layer on top of the engine that supports the servlet API is thin, and it should be possible to integrate it with other frameworks/libraries, but at this moment I know of no one who has attempted to integrate DirectJNgine with Struts 2.

That said, I think you can install the DJN servlet and make it coexist with Struts 2, but whether this is applicable will depend on how you plan to use DJN. Deep integration might require extra work, but just using it to handle some chores should be possible.

Whatty
25 Nov 2009, 8:27 AM
Good morning,

We have been working with the djn-spring-1.1-rc1 library and have made a bunch of updates to the Spring Integration adding support for sessions.

I have attached the source code and configuration files required for this to work.

Basically it attempts to locate the Spring bean in the session first and if found uses that instance for invocation of the method, otherwise it asks Spring for the appropriately named bean.

This is a very very rough first attempt at it and believe me there are many many opportunities for refactoring and improving this code but I wanted to get it out there for others to take a look at, possibly use and suggest improvements.

Whatty

pagullo
26 Nov 2009, 12:18 AM
Hi!

After several request from DJN users I have dedided to add support for making it possible to access the following information easily from a DJN method:



HttpSession
ServletContext
HttpServletRequest
HttpServletResponse
HttpServlet
ServletConfig


Besides, I am providing support for session and application scoped actions too.

I have implemented this as an extension built on top of the DJN core, as I strongly feel that state management is an orthogonal concern, but I will include this in the same JAR, to make things easy :)

Here is what I plan to support...

Accessing the session, request, response, etc. from a DJN method
You can acces the session, servlet context, request, response, servlet and servlet configuration using the WebContext and WebContextManager classes, as shown in the following code:


public class WebContextManagerTest {
public static class WebContextInfo {
public int callsInSession = 0;
public int callsInApplication = 0;
public String sessionId;
}

@DirectMethod
public WebContextInfo test_webContext() {
WebContext context = WebContextManager.get();
HttpSession session = context.getSession();
ServletContext application = context.getServletContext();

// Keep a counter of how many times we have called
// this method in this session
Integer callsInSession =
(Integer)session.getAttribute("callsInSession");
if( callsInSession == null ) {
callsInSession = new Integer(0);
}
callsInSession = new Integer(callsInSession.intValue() + 1);
session.setAttribute("callsInSession", callsInSession);

// Keep a counter of how many times we have called
// this method in this application
Integer callsInApplication =
(Integer)application.getAttribute("callsInApplication");
if( callsInApplication == null ) {
callsInApplication = new Integer(0);
}
callsInApplication =
new Integer(callsInApplication.intValue() + 1);
application.setAttribute("callsInApplication",
callsInApplication);

// Return status information
WebContextInfo result = new WebContextInfo();
result.callsInApplication = callsInApplication.intValue();
result.callsInSession = callsInSession.intValue();
result.sessionId = context.getSession().getId();
return result;
}
}
Making an action session-scoped
To make an action session-scoped, just use the @ActionScope annotation as follows:



@ActionScope(scope=Scope.SESSION)
public class SessionStatefulActionTest {
private int count = 0;

@DirectMethod
public synchronized int test_getSessionCallCount() {
this.count++;
return this.count;
}
}
Note how the only thing you need to do is to add the @ActionScope annotation.

Making an action application-scoped
To make an action application-scoped, just use the @ActionScope annotation as follows:



@ActionScope(scope=Scope.APPLICATION)
public class ApplicationStatefulActionTest {

private int data = 0;
private int count = 0;
private int pollData = 0;

@DirectMethod
public synchronized int test_getApplicationData() {
this.data++;
int result = this.data;

// Trick to allow multiple test executions
if( this.data == 2) {
this.data = 0;
}
return result;
}

@DirectMethod
public synchronized int test_getApplicationCallCount() {
this.count++;
return this.count;
}

Again, the only thing you need to do is to use the @ActionScope annotation.

This functionality is currently in alpha, and feedback from DJN users will be welcome. I haven't polished all concurrency related issues, and will greatly appreciate you guys take a look at it.

The attached JARs include the corresponding classes and source code.

@vlagorce & other people working in DJN extensions
Since some DJN internals have changed to make the DJN core completely independent of state management, you will probably have to make some little changes to your code. Sorry about that, guys.


Besides, for those interested in having session and application scoped actions, you will probably be able to rely on the new functionality provided by DJN instead of having to implement it on your own.

dreamtaotao
26 Nov 2009, 7:11 AM
I am pleased to DirectJNgine becoming more and more powerful. Just seen DirectJNgine-Spring, regret that so little information and no examples and documentation, and I hope we can DirectJNgine combined with the spring should be nice to do! I wish you success in your work that I have been watching the better DirectJNgine!

Whatty
26 Nov 2009, 11:08 AM
Pedro,

First of all thank you very much for addressing Session support in the DirectJNgine.

Having taken a look at the update, and already integrated it with the SessionAware spring integrator that I posted yesterday, I would like to suggest a simple modification to the RequestProcessorBase class that I believe will make it easier for integrating other bean controllers such as Spring

In the method below, you grab the RegisteredMethod in which to service the request and allow the dispatcher to execute the method against the action instance



protected Object dispatch(Class<?> instanceClass, Method method, Object[] parameters) {
return getDispatcher().dispatch( instanceClass, method, parameters );
}

// TODO: this is NOT something PollRequestProcessor will use. Handle somewhere else!
protected Object dispatch( String actionName, String methodName, Object[] parameters ) {
assert !StringUtils.isEmpty(actionName);
assert !StringUtils.isEmpty(methodName);
assert parameters != null;

RegisteredMethod method = getMethod( actionName, methodName);
Object result = dispatch(method.getActionClass(), method.getMethod(), parameters);
return result;
}


Since you pull the information out of the RegisteredMethod to make the call to dispatch method, you essentially loose track of the actionName. This action name is used by Spring to initiate the bean lookup.

I had to override the JSON request processor to handle this situation as below:



protected Object dispatch( String actionName, String methodName, Object[] parameters ) {
assert !StringUtils.isEmpty(actionName);
assert !StringUtils.isEmpty(methodName);
assert parameters != null;


RegisteredMethod method = this.getMethod(actionName, methodName);

LOGGER.debug("actionName = " + method.getActionName() + ", methodName = " + method.getMethod().getName());

Object result = this.dispatch(method, parameters);
return result;
}

protected Object dispatch(RegisteredMethod method, Object[] parameters) {
return ((SessionAwareSpringDispatcher)this.getDispatcher()).dispatch(method, parameters);
}


where instead of pulling the information out of the RegisteredMethod, I just pass it to the dispatcher. This makes action name available to the dispatcher, which I then use to lookup up the bean in the Spring Context.

I could have used the action class name, but this puts an invalid dependency on the action name to class name association.

I believe this small refactoring would make it easier for people to override the default behavior in the dispatch hierarchy for action instantiation, or in my case bean lookup by action name.

Again I thank you and I am sure the community thanks you for your efforts.

Whatty

Whatty
26 Nov 2009, 1:48 PM
Good afternoon,

I have quickly updated the session aware Spring Integrator that I posted a few days ago to make the latest version of the DirectJngine 1.2-Alpha1.

Again, it is very very rough and could probably do with some refactoring / cleanup but but is functional.

To the author of the original Spring Integration, I updated some of your classes to match the new DirectJngine so please take a look.

MMV (mileage may vary)

Whatty

pagullo
26 Nov 2009, 11:57 PM
Pedro,

First of all thank you very much for addressing Session support in the DirectJNgine.

Having taken a look at the update, and already integrated it with the SessionAware spring integrator that I posted yesterday, I would like to suggest a simple modification to the RequestProcessorBase class that I believe will make it easier for integrating other bean controllers such as Spring

In the method below, you grab the RegisteredMethod in which to service the request and allow the dispatcher to execute the method against the action instance



protected Object dispatch(Class<?> instanceClass, Method method, Object[] parameters) {
return getDispatcher().dispatch( instanceClass, method, parameters );
}

// TODO: this is NOT something PollRequestProcessor will use. Handle somewhere else!
protected Object dispatch( String actionName, String methodName, Object[] parameters ) {
assert !StringUtils.isEmpty(actionName);
assert !StringUtils.isEmpty(methodName);
assert parameters != null;

RegisteredMethod method = getMethod( actionName, methodName);
Object result = dispatch(method.getActionClass(), method.getMethod(), parameters);
return result;
}
Since you pull the information out of the RegisteredMethod to make the call to dispatch method, you essentially loose track of the actionName. This action name is used by Spring to initiate the bean lookup.

I had to override the JSON request processor to handle this situation as below:



protected Object dispatch( String actionName, String methodName, Object[] parameters ) {
assert !StringUtils.isEmpty(actionName);
assert !StringUtils.isEmpty(methodName);
assert parameters != null;


RegisteredMethod method = this.getMethod(actionName, methodName);

LOGGER.debug("actionName = " + method.getActionName() + ", methodName = " + method.getMethod().getName());

Object result = this.dispatch(method, parameters);
return result;
}

protected Object dispatch(RegisteredMethod method, Object[] parameters) {
return ((SessionAwareSpringDispatcher)this.getDispatcher()).dispatch(method, parameters);
}
where instead of pulling the information out of the RegisteredMethod, I just pass it to the dispatcher. This makes action name available to the dispatcher, which I then use to lookup up the bean in the Spring Context.

I could have used the action class name, but this puts an invalid dependency on the action name to class name association.

I believe this small refactoring would make it easier for people to override the default behavior in the dispatch hierarchy for action instantiation, or in my case bean lookup by action name.

Again I thank you and I am sure the community thanks you for your efforts.

Whatty

Hi!

I didn't do it the way you suggest because poll methods need to be taken into account too, and I implemented them so they are 'global', i.e., they do not belong to a RegisteredAction, and therefore I can't pass the action name to the dispatch method for poll methods (sigh).

But I can pass the class, and it is really useful sometimes, for example to process custom annotations -which is what I do to support stateful actions.

As to way poll methods do not belong to a RegisteredAction, that made lots of sense when we had no stateful actions, as it made implementing some things much easier back then. Changing that now would change the published API...but I might do, because that part of the API is rarely used, to be fair...On the other hand, I was aware that if I had made that change, I would have had the RegisteredAction available, and passing that to dispatch would make additional info available, including the action name you want...

So, I need to consider carefully how or whether to pass the additional info you suggest. Let me think about that, ok?

Thanks for the feedback :)

Best regards,

lxbzmy
27 Nov 2009, 12:19 AM
can not call a directmethod when a string param contains \n \r etc?
why?

pagullo
27 Nov 2009, 2:43 AM
can not call a directmethod when a string param contains \n \r etc?
why?

Make our life easier and provide additional info, please: js & java source code, exception traces, request/response logs, error logs, etc.

Take into account that the one in charge of JSON processing is the GSON library, so it might be due to some issue with it, be it a bug or just we having to adjust GSON in some way -or just using it the wrong way.

Whatty
27 Nov 2009, 5:16 AM
Hi!

I didn't do it the way you suggest because poll methods need to be taken into account too, and I implemented them so they are 'global', i.e., they do not belong to a RegisteredAction, and therefore I can't pass the action name to the dispatch method for poll methods (sigh).

But I can pass the class, and it is really useful sometimes, for example to process custom annotations -which is what I do to support stateful actions.

As to way poll methods do not belong to a RegisteredAction, that made lots of sense when we had no stateful actions, as it made implementing some things much easier back then. Changing that now would change the published API...but I might do, because that part of the API is rarely used, to be fair...On the other hand, I was aware that if I had made that change, I would have had the RegisteredAction available, and passing that to dispatch would make additional info available, including the action name you want...

So, I need to consider carefully how or whether to pass the additional info you suggest. Let me think about that, ok?

Thanks for the feedback :)

Best regards,

If you take a look at my post with the Session Aware Spring integrator you will quickly see the problem that I face.

In the class


SessionAwareSpringDispatcher

you will see that I had to essentially override a number of methods in not so nice manner.

I understand that you are supporting a more generic framework so anything that you could do to provide additional hooks or information into the generic framework would be appreciated.

Thanks

Whatty

GregT
27 Nov 2009, 2:08 PM
Hi Pedro,

I get this OOM error from Tomcat a few times a day. I am wondering if it is a leak in the YUI Compressor, and that it happens proportional to how often you recompile the classes that DJN is looking for. I assume this triggers a rebuild of Api.js, which is the only thing on my system that I know of that might run YUI. Any thoughts? Should I try to track down a better compressor? Do you have any experience with this problem? First few lines of the stack trace follows.

Thanks,
Greg

Nov 27, 2009 12:55:31 PM org.apache.catalina.core.ApplicationContext log
SEVERE: StandardWrapper.Throwable
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.util.Arrays.copyOf(Unknown Source)
at java.util.ArrayList.ensureCapacity(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.<clinit>(JavaScriptCompressor.java:69)
at com.softwarementors.extjs.djn.jscodegen.Minifier.minify(Minifier.java:42)

pagullo
28 Nov 2009, 2:08 AM
Hi Pedro,

I get this OOM error from Tomcat a few times a day. I am wondering if it is a leak in the YUI Compressor, and that it happens proportional to how often you recompile the classes that DJN is looking for. I assume this triggers a rebuild of Api.js, which is the only thing on my system that I know of that might run YUI. Any thoughts? Should I try to track down a better compressor? Do you have any experience with this problem? First few lines of the stack trace follows.

Thanks,
Greg

Nov 27, 2009 12:55:31 PM org.apache.catalina.core.ApplicationContext log
SEVERE: StandardWrapper.Throwable
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.util.Arrays.copyOf(Unknown Source)
at java.util.ArrayList.ensureCapacity(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
at com.yahoo.platform.yui.compressor.JavaScriptCompressor.<clinit>(JavaScriptCompressor.java:69)
at com.softwarementors.extjs.djn.jscodegen.Minifier.minify(Minifier.java:42)

Greg,

No, I haven't seen this problem before. Ugly one :(.

Difficult to know whether this is some issue with the YUI Compressor, the way DJN handles the compressor, or even your app: this last possibility might sound crazy, but there might be some app-related memory leak that is made visible only when the compressor starts working because it is very memory hungry and hence is the first piece of code to reach some upper limit.

Can you post the whole stack trace?

On the other hand, how much memory does Tomcat have? Have you tried to modify the amount of memory Tomcat uses? Can you monitor how memory is used by Tomcat? Is there some trend?

If at all possible, check memory usage with the 'minify' option set to true and then to false, just to check the trend in memory usage in both scenarios.

Hmmm... Why don't you patch the DJN code that minifies the js code to log the amount of memory used by the VM before/after every compression? Maybe you will be able to find some trend...

Everything else failing, the workaround will be to set the 'minify' option to false.

Let us know how it goes.

Ramez
30 Nov 2009, 2:49 PM
Hi Pedro,

We recently moved all our Prototype based AJAX calls over to using Ext.Direct with DirectJNgine. Most of the conversion process was relatively straight forward but we have run into a problem with a few calls that rely on values pulled from a client's session.

To facilitate this we implemented a Filter that pulls the session out for later use by various Direct methods. This approach seems to work for the most part, but we've noticed an issue with the Filter not being called when a call that relies on it is batched with another call. If filter is not called, when a method goes to get the session value as stored by the Filter, it will be null since doFilter is not being called.

Here's what the stack trace looks like when the Filter is properly called and we are able to extract the session values for use in the Direct method:



MyClass.mySessionReliantMethod(String) line: 967
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
Dispatcher.invokeMethod(Method, Object, Object[]) line: 113
Dispatcher.dispatch(Class<?>, Method, Object[]) line: 55
JsonRequestProcessor(RequestProcessorBase).dispatch(Class<?>, Method, Object[]) line: 219
JsonRequestProcessor(RequestProcessorBase).dispatch(String, String, Object[]) line: 230
JsonRequestProcessor.processIndividualRequest(JsonRequest, boolean, int) line: 368
JsonRequestProcessor.processIndividualRequestsInThisThread(JsonRequest[]) line: 127
JsonRequestProcessor.process(Reader, Writer) line: 109
RequestRouter.processJsonRequest(Reader, Writer) line: 77
DirectJNgineServlet.doPost(HttpServletRequest, HttpServletResponse) line: 377
DirectJNgineServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 637
DirectJNgineServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 717
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 290
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
SessionFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 57
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
EncodingUTF8Filter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 25
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
LocalAddrFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 52
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206
StandardWrapperValve.invoke(Request, Response) line: 233
StandardContextValve.invoke(Request, Response) line: 191
SSLWithFormFallbackAuthenticator.invoke(Request, Response) line: not available
StandardHostValve.invoke(Request, Response) line: 128
ErrorReportValve.invoke(Request, Response) line: 102
StandardEngineValve.invoke(Request, Response) line: 109
CoyoteAdapter.service(Request, Response) line: 293
Http11Processor.process(Socket) line: 849
Http11Protocol$Http11ConnectionHandler.process(Socket) line: 583
JIoEndpoint$Worker.run() line: 454
Thread.run() line: 619 [local variables unavailable] Here's what the stack trace looks like when the Filter is not called, as is the case when calls are batched together:



MyClass.mySessionReliantMethod(String) line: 967
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
Dispatcher.invokeMethod(Method, Object, Object[]) line: 113
Dispatcher.dispatch(Class<?>, Method, Object[]) line: 55
JsonRequestProcessor(RequestProcessorBase).dispatch(Class<?>, Method, Object[]) line: 219
JsonRequestProcessor(RequestProcessorBase).dispatch(String, String, Object[]) line: 230
JsonRequestProcessor.processIndividualRequest(JsonRequest, boolean, int) line: 368
JsonRequestProcessor.access$000(JsonRequestProcessor, JsonRequest, boolean, int) line: 66
JsonRequestProcessor$1IndividualRequestProcessor.call() line: 148
JsonRequestProcessor$1IndividualRequestProcessor.call() line: 140
FutureTask$Sync.innerRun() line: 303
ParallelTask$BoundedFuture(FutureTask<V>).run() line: 138 [local variables unavailable]
ThreadPoolExecutor$Worker.runTask(Runnable) line: 886
ThreadPoolExecutor$Worker.run() line: 908 [local variables unavailable]
Thread.run() line: 619
We'd like to keep the ability to batch calls and the optimal solution would be that ability to ensure that requests that are batched are filtered as expected. Another option would be if we could force this one method not to be batched.

We are using version DirectJNgine 1.0 due to licensing constraints incurred by 1.1's move to GPLv3.

Any help you can give would be greatly appreciated.

pagullo
1 Dec 2009, 10:30 AM
Hi!

The issue you have is probably due to the fact that you are (probably) storing your request, etc. data in a thread local variable, BUT that will not be available to the newly created threads that run the individual requests in a batch.

Frankly speaking, processing batched request via multiple threads is an optimization you will probably not really need (I know of no other Ext Direct stack that does that, in fact, and nobody has complained so far...). So, the easier way to solve this is to set the corresponding configuration setting to false -as I already mentioned in other post.

That said, I have already implemented the equivalent of the filter you developed due to popular demand, of course supporting multithreaded batched requests processing. I will publish this one in alpha 2 of Ext Direct 1.2 real soon.

You need not worry about the license change in 1.1, it is both a silly and unintended mistake I already discussed in this thread: 1.2 final will be published with an LGPL v3 license, which is what I always meant :).

Therefore, you might want to keep using whatever you have now with the workaround mentioned above, and wait for 1.2 final and use the new built-in mechanism for accesing the request, response, session, servlet context and servlet configuration :).

Best regards,

Ramez
1 Dec 2009, 1:47 PM
Thanks for the support Pedro.

Your assumption about storing the session in a thread local variable was correct.

After adding the init-param to disable multithreading of batch requests to our web.xml, all Ext.Direct calls succeed as expected.

Thanks for the heads up the regards to the planned change in licensing for 1.2. Do you have any idea of the time frame in which the 1.2 alpha might be available?

maho2nd
3 Dec 2009, 1:42 AM
Hi,

I like to send some requests as a batch to the server (no multithreading!).

Is something like this possible?


public class TestAction {

private int calls = 0;

@DirectMethod
public String doEcho( String data ) {
calls ++;

if(calls == 5)
//do something

return data;
}

public String doSomething( String data ) {
calls ++;

if(calls == 5)
//do something

return data;
}


Edit:
I think I need something like this: @ActionScope(scope=Scope.BATCH)

pagullo
3 Dec 2009, 5:07 AM
Hi,

I like to send some requests as a batch to the server (no multithreading!).

Is something like this possible?


public class TestAction {

private int calls = 0;

@DirectMethod
public String doEcho( String data ) {
calls ++;

if(calls == 5)
//do something

return data;
}

public String doSomething( String data ) {
calls ++;

if(calls == 5)
//do something

return data;
}
Edit:
I think I need something like this: @ActionScope(scope=Scope.BATCH)


Yes, it is, but only from DJN 1.2 onwards, using either session/application scoped actions or the new WebContext class. 1.2 is currently in alpha, check post #155 to get it and know what's there.

Of course, since what I have is an alpha, things might change, but I hope not that much.

BTW, in alpha 1 there is no support for multithreaded batched request, set the corresponding configuration flag to false...

maho2nd
3 Dec 2009, 5:24 AM
Yes, it is, but only from DJN 1.2 onwards, using either session/application scoped actions or the new WebContext class. 1.2 is currently in alpha, check post #155 to get it and know what's there.

Of course, since what I have is an alpha, things might change, but I hope not that much.

BTW, in alpha 1 there is no support for multithreaded batched request, set the corresponding configuration flag to false...

Thanks for your response!

I read the post #155 but i thought Scope.Applications would save the private variables for the whole runtime and not only for a batch request. Because I need it only for the batch request.

I tested the Scope.Applications Annotation by modify your demo , but it didn't worked:



@ActionScope(scope=Scope.APPLICATION)
public class DirectStoreDemo {
private int count = 0;

[..]

@DirectMethod
public synchronized void addCounter() {

this.count++;

}

@DirectMethod
public synchronized List<Experience> djn_loadExperienceData() {

this.count++;

List<Experience> items = new ArrayList<Experience>();
Collections.addAll( items,
new Experience( String.valueOf(count), "", "Programming, design and analysis in many projects, using Java, C#, C++, Smalltalk, Delphi, C"),[...]
);
return items;
}


web.xml:


<init-param>
<param-name>batchRequestsMultithreadingEnabled</param-name>
<param-value>false</param-value>
</init-param>


In my script I call addCounter() multiple times an then I load a Grid with the data of
loadExperienceData. But String.valueOf(count) is always 1. Firebug shows that all calls are send in 1 request.

Can you help me?

pagullo
3 Dec 2009, 11:30 PM
can not call a directmethod when a string param contains \n \r etc?
why?

The problems lies with the ExtDirect infrastructure, which is the one in charge of generating the JSON-encoded requests: ExtJs is not escaping the strings it sends to JSON, and therefore when the JSON encoded request reaches GSON, it just rejects strings having unescaped '\n' or '\r' characters -I think that is the right behaviour, according to what the JSON spec says with regard to strings.

As a workaround, you can escape strings before you send them. Passing


'a\\\\nb\\\\r\c'in javascript to a direct method that just returns the received string will end up in


'a\nb\rc'being returned to Javascript, as proved by the following test:

Javascript:


test_serverCallWithNewLineCharacters : function() {
ServerMethodParametersReceptionTest.test_serverCallWithNewLineCharacters(
'a\\\\nb\\\\r\c',
function(provider, response) {
Djn.Test.checkSuccessfulResponse( "test_serverCallWithNewLineCharacters",
response, response.result === 'a\nb\rc', response.result);
}
);
},
Java code:


@DirectMethod
public String test_serverCallWithNewLineCharacters( String arg ) {
if( !arg.contains("\n") || !arg.contains( "\r"))
throw new DirectTestFailedException(
"We expected that method to have have the \\n and \\r characters");

return arg;
}

pagullo
4 Dec 2009, 12:13 AM
Thanks for your response!

I read the post #155 but i thought Scope.Applications would save the private variables for the whole runtime and not only for a batch request. Because I need it only for the batch request.

I tested the Scope.Applications Annotation by modify your demo , but it didn't worked:



@ActionScope(scope=Scope.APPLICATION)
public class DirectStoreDemo {
private int count = 0;

[..]

@DirectMethod
public synchronized void addCounter() {

this.count++;

}

@DirectMethod
public synchronized List<Experience> djn_loadExperienceData() {

this.count++;

List<Experience> items = new ArrayList<Experience>();
Collections.addAll( items,
new Experience( String.valueOf(count), "", "Programming, design and analysis in many projects, using Java, C#, C++, Smalltalk, Delphi, C"),[...]
);
return items;
}
web.xml:


<init-param>
<param-name>batchRequestsMultithreadingEnabled</param-name>
<param-value>false</param-value>
</init-param>
In my script I call addCounter() multiple times an then I load a Grid with the data of
loadExperienceData. But String.valueOf(count) is always 1. Firebug shows that all calls are send in 1 request.

Can you help me?

Ooops, I *completely* missed your 'Scope.BATCH' thing, so I answered assuming you were using one of the supported scopes.

I do not plan on supporting that kind of scope, and to be fair I'm not sure it makes sense to add such a thing as a general purpose construction.

With regard to your modification to the test application, it works perfectly well for me: the counter is correctly incremented every time I reload the page. And other users are using the Scope.APPLICATION happily.

Hmm. Maybe you are inadvertently mixing the 1.2 alpha clasess with the 1.1 classes in the test app?

That would explain that you can use the annotation (because it is found by your web server) but it does not have effect (maybe because the app is loading the old versions of the DJN classes).

maho2nd
7 Dec 2009, 12:04 AM
Hmm. Maybe you are inadvertently mixing the 1.2 alpha clasess with the 1.1 classes in the test app?
Thanks, that was the problem!


I do not plan on supporting that kind of scope, and to be fair I'm not sure it makes sense to add such a thing as a general purpose construction.
It could be helpful, if you have some dependent requests which should be send as one request to the server. Then if one of the for example 3 requests fails, you can rollback the database transaction. But maybe there is better solution without using a Scope.Batch.

GregT
8 Dec 2009, 6:10 PM
Hi Pedro,

Back on 11-27-2009 I posted a message on this thread regarding OOM errors, YUI compressor and DJN. Just wanted to let you know that I am now fairly convinced that this is a flaw in Tomcat. Basically, from testing and Googling, it seems you cannot reliably reload classes in Tomcat without eventually encountering OOM. The solution is either to restart it every time, or, perhaps, use JRebel. In any case, I don't think DJN is implicated.

On another topic, off the top of your head, can I use something like request.getSession() via DJN? Eg. I want to know the session ID related to the request that DJN just handed me. I have not looked into this at all, just thought I'd throw it out there, it's probably a RTFM.

Thanks again and as always, Happy Holidays.
Greg

pagullo
8 Dec 2009, 11:14 PM
Hi Pedro,

Back on 11-27-2009 I posted a message on this thread regarding OOM errors, YUI compressor and DJN. Just wanted to let you know that I am now fairly convinced that this is a flaw in Tomcat. Basically, from testing and Googling, it seems you cannot reliably reload classes in Tomcat without eventually encountering OOM. The solution is either to restart it every time, or, perhaps, use JRebel. In any case, I don't think DJN is implicated.

On another topic, off the top of your head, can I use something like request.getSession() via DJN? Eg. I want to know the session ID related to the request that DJN just handed me. I have not looked into this at all, just thought I'd throw it out there, it's probably a RTFM.

Thanks again and as always, Happy Holidays.
Greg

Thanks, Greg, I will close the issue.

And, yes, you can access the request, session, etc. by using the WebContext and WebContextManager classes. This is a new feature in the latest 1.2 alpha.

See posting #155 for details.

Best regards,

J@y
13 Dec 2009, 7:06 PM
Hi Pedro,

Is there any version of DJN which does not include Spring support?

PS: stupid me, ignore my question please lol
1.2 alpha should be the thing that I'm looking for.

jcalfee
1 Jan 2010, 4:58 PM
Please post an example of calling a method on a remote host. There is some sort of Direct iframe proxy that should allows this to work with DirectJNgine. This could lay the groundwork for a very useful JSON web services network.

lxbzmy
1 Jan 2010, 7:11 PM
The problems lies with the ExtDirect infrastructure, which is the one in charge of generating the JSON-encoded requests: ExtJs is not escaping the strings it sends to JSON, and therefore when the JSON encoded request reaches GSON, it just rejects strings having unescaped '\n' or '\r' characters -I think that is the right behaviour, according to what the JSON spec says with regard to strings.

As a workaround, you can escape strings before you send them. Passing


'a\\\\nb\\\\r\c'in javascript to a direct method that just returns the received string will end up in


'a\nb\rc'being returned to Javascript, as proved by the following test:

Javascript:


test_serverCallWithNewLineCharacters : function() {
ServerMethodParametersReceptionTest.test_serverCallWithNewLineCharacters(
'a\\\\nb\\\\r\c',
function(provider, response) {
Djn.Test.checkSuccessfulResponse( "test_serverCallWithNewLineCharacters",
response, response.result === 'a\nb\rc', response.result);
}
);
},
Java code:


@DirectMethod
public String test_serverCallWithNewLineCharacters( String arg ) {
if( !arg.contains("\n") || !arg.contains( "\r"))
throw new DirectTestFailedException(
"We expected that method to have have the \\n and \\r characters");

return arg;
}


Extdirect php example execute successfull! when have \n in string .
but djn failure. because djn decode hole json first and not encode them then.


JsonRequestProcessor.java

private Object[] jsonStringToMethodParameters(RegisteredMethod method, String jsonParametersString, Class<?>[] parameterTypes, boolean debug) {
...
JsonElement[] jsonParameters = getJsonElements(jsonParametersString);
Object[] result = getMethodParameters(parameterTypes, jsonParameters);
//json decoded if \n in string \n become a new line
...


private Object[] getMethodParameters(Class<?>[] parameterTypes, JsonElement[] jsonParameters) {

JsonElement jsonValue = jsonParameters[i];
String json = jsonValue.toString();
//^ you simple use tostring method but jsonValue.toString() can not escape \n in string
// jsonValue.toStirng()'s result is not a //valid json format
// here must re encode to json format or add a Method toJSONString() i gson
Object value = getGson().fromJson(json, parameterTypes[i]);
//exception thrown here

GregT
9 Jan 2010, 5:58 AM
Hi Pedro and Happy New Year,

I came across this problem. I have a method being called via DJN that includes an incoming type that is a custom subclass of the standard ArrayList (eg. 'class MyList extends ArrayList'). Everything compiles correctly but when I run it and call that method, I get this message:

IllegalArgumentException: Can not set MyList field myList to java.util.LinkedList

This happens while making the method call and it never gets to the first line of code inside the method. Upon poking around in your source and reading documentation, I think the core limitation is in GSON. Per the GSON documentation:

Collections Limitations



Can serialize collection of arbitrary objects but can not deserialize from it

Because there is no way for the user to indicate the type of the resulting object

While deserializing, Collection must be of a specific generic type

All of this makes sense, and is rarely a problem when following good Java coding practices


I do not understand why what I am doing is considered by GSON to be a bad coding practice, but never mind that. More importantly, I'm not sure why GSON can't discover the correct subclass using Reflection or whatever it is that they do, same as any other type. Actually I'm not certain that I understand this problem correctly at all. Maybe it has something to do with generic type erasure.

Wondering if you had any thoughts on this?

GregT
9 Jan 2010, 9:17 PM
Also Pedro I wonder if you could just confirm that I understand the basics of DJN marshalling correctly. Suppose in Java I have this:

Class DjnTest {
public void DoThis(String myThing) {}
}

In JS, I believe this is what happens under various scenarios (slightly simplified code for clarify, I am sure you see the point I am getting at):

1. x = {myThing : 'foo'}; DjnTest.DoThis(x). Result in Java: myThing is equal to 'foo'. This would be the normal operation.

2. x = {yourThing : 'foo'}; DjnTest.DoThis(x). Result in Java: myThing is equal to 'null', and the value I gave 'yourThing' is silently discarded.

3. x = {myThing : 'foo'}; y = 'test', DjnTest.DoThis(x,y). Result: normal JS calling semantics cause DoThis to be called and the value of 'y' to be ignored. In Java, this looks the same as example #1.

4. DjnTest.DoThis(). Result: normal JS calling semantics cause DoThis to be called and the value of 'myThing' in Java to be set to 'null'. In Java, this looks the same as #2.

I believe that in all of these examples, no JS or Java-side error messages would appear anywhere. (I am not saying this is wrong or anything like that, I'm just trying to understand it. I think this is all rather basic, I just want to make sure I have it right?)

pagullo
11 Jan 2010, 2:31 AM
Hi Pedro and Happy New Year,


Thanks :)!



I came across this problem. I have a method being called via DJN that includes an incoming type that is a custom subclass of the standard ArrayList (eg. 'class MyList extends ArrayList'). Everything compiles correctly but when I run it and call that method, I get this message:

IllegalArgumentException: Can not set MyList field myList to java.util.LinkedList

This happens while making the method call and it never gets to the first line of code inside the method. Upon poking around in your source and reading documentation, I think the core limitation is in GSON. Per the GSON documentation:

Collections Limitations



Can serialize collection of arbitrary objects but can not deserialize from it

Because there is no way for the user to indicate the type of the resulting object


While deserializing, Collection must be of a specific generic type

All of this makes sense, and is rarely a problem when following good Java coding practices


I do not understand why what I am doing is considered by GSON to be a bad coding practice, but never mind that. More importantly, I'm not sure why GSON can't discover the correct subclass using Reflection or whatever it is that they do, same as any other type. Actually I'm not certain that I understand this problem correctly at all. Maybe it has something to do with generic type erasure.

Wondering if you had any thoughts on this?
I need to check your Java code to give you an informed opinion.

That said, the error message is "Can not set MyList field myList to java.util.LinkedList". Please, note that the message signals assignment to a field as problematic: it looks as if the problem were related to attempting to assign a LinkedList to what is declared to be a MyList (is MyList a LinkedList subclass? I guess not).

But I'm just guessing: post your code for methods and classes being passed back and forth, and let us take a look at it.

With regards to collections, I try to use the simplest kinds of collections as parameters/return types for djn methods (lists, arrays...), to avoid getting into potentially problematic issues. 99% of the JSON parsing is done by Gson: it is a very robust library, and you can customize it, but it is usually better to make things simple.

pagullo
11 Jan 2010, 3:15 AM
Also Pedro I wonder if you could just confirm that I understand the basics of DJN marshalling correctly. Suppose in Java I have this:

Class DjnTest {
public void DoThis(String myThing) {}
}

In JS, I believe this is what happens under various scenarios (slightly simplified code for clarify, I am sure you see the point I am getting at):

1. x = {myThing : 'foo'}; DjnTest.DoThis(x). Result in Java: myThing is equal to 'foo'. This would be the normal operation.

2. x = {yourThing : 'foo'}; DjnTest.DoThis(x). Result in Java: myThing is equal to 'null', and the value I gave 'yourThing' is silently discarded.

3. x = {myThing : 'foo'}; y = 'test', DjnTest.DoThis(x,y). Result: normal JS calling semantics cause DoThis to be called and the value of 'y' to be ignored. In Java, this looks the same as example #1.

4. DjnTest.DoThis(). Result: normal JS calling semantics cause DoThis to be called and the value of 'myThing' in Java to be set to 'null'. In Java, this looks the same as #2.

I believe that in all of these examples, no JS or Java-side error messages would appear anywhere. (I am not saying this is wrong or anything like that, I'm just trying to understand it. I think this is all rather basic, I just want to make sure I have it right?)

Greg,

1 and 2 are ok, but not 3 and 4.

Here is a "quick and dirty" guide to how data is copied from javascript objects to java objects, as well as how excess/missing parameters in a methdo call are handled...

Passing objects
The rules for passing object back and forth are dictated by

a) the GSON library, which is the one in charge of converting JSON to Java objects.
b) ExtJs, which is the one in charge of converting Javascript objects to JSON.

If I recall correctly, the (fast & informal) rule is as follows:

a) all fields in Java objects are copied to the js object, including those with a null value (you can change that via customization, though). Transient fields are not copied.

b) all fields in a Javascript object that have a corresponding Java field are passed to Java classes, except those that have undefined as value. Those javascript fields with no corresponding Java field are ignored.

For the exact rules, check both GSON and ExtJs documentation: take into account that you can customize many, many things in GSON.

Number of arguments for methods
When it comes to methods, you must call them with the exact number of parameters, and it is considered a bug not to do so: i.e., this is something you must make sure does not happen in the javascript side, instead of something you must react to.

I you need to pass a variable list of arguments of the same kind, consider using a list or array as the last parameter. For a variable list of arguments of heterogenous types, take a look at the "Handling JSON data directly" chapter in the User's Guide.


Best regards,

GregT
11 Jan 2010, 7:27 AM
Thanks very much, Pedro. I'm on a different project today; I will send you a specific example later in the week. Just to clarify though, my code never references 'LinkedList' directly and yes, MyList is not a subclass of LinkedList (and I don't want it to be).

It appears that DJN/GSON is creating a LinkedList because it's not really sure which collection type to use. A simple workaround is to make the parameter a LinkedList and immediately copy it into MyList. I'm fine with that, I'm just trying to understand this issue thoroughly.

pagullo
12 Jan 2010, 10:55 AM
can not call a directmethod when a string param contains \n \r

I misdiagnosed this. It is fixed, and it will make into the next version of DJN.

GregT
12 Jan 2010, 7:01 PM
Hi Pedro,

Here is an example of the LinkedList vs. ArrayList issue that I was talking about a couple of posts back. I hope I have succeeded in stripping this down to the essentials...



// Like a java.util.List, but silently eats any duplicate entries
public class UniqueList<E> extends ArrayList<E> {
public UniqueList() {
super();
}
public boolean add(E object) {
if (object == null)
throw new NullPointerException();
if (this.contains(object))
return false;
else {
super.add(object);
return true;
}
}
}

// Represents a request from Ext. In real life this would contain more than just the
// UniqueList, but this is good enough for an example.
public class ExtRequest {
public UniqueList<String> s;
}

// Accepts an ExtRequest from Tomcat. In real life we would return an object representing
// some work we did based on what's inside the ExtRequest.
public class Server {
public Server () {}
public void djn_getData (ExtRequest extRequest) {}
}


So, if on the Ext side you create an ExtRequest and call Server.djn_getData, you should see the error referencing LinkedList. As I mentioned before, my code never references a LinkedList, so I think it is coming out of the GSON marshalling logic.

There are several simple workarounds to this, so I am mostly just asking about this out of curiosity and desire to understand the whole thing better. If I can clarify anything further, please let me know.

set_ti
15 Jan 2010, 12:11 AM
Hi,

ive a problem using directjngine with forms.
Ive created a form with a checkboxgroup like this:


id : 'projects',
fieldLabel : 'Projects',
name : 'projects',
xtype : 'checkboxgroup',
columns : 3,
allowBlank : false,
items : [
{boxLabel: 'A', name: 'projects', inputValue: 'A'},
{boxLabel: 'B', name: 'projects', inputValue: 'B'},
{boxLabel: 'C', name: 'projects', inputValue: 'C'},
{boxLabel: 'D', name: 'projects', inputValue: 'D'},
{boxLabel: 'E', name: 'projects', inputValue: 'E'}
]
In a normal servlet i would use
request.getParameterValues("projects") and get a String array which i can iterate.
But how should i use the formParameters map parameter of the @DirectFormPostMethod, which i guess does not allow multiple keys?!

Can you give me any hint?

pagullo
18 Jan 2010, 4:47 AM
Hi,

ive a problem using directjngine with forms.
Ive created a form with a checkboxgroup like this:


id : 'projects',
fieldLabel : 'Projects',
name : 'projects',
xtype : 'checkboxgroup',
columns : 3,
allowBlank : false,
items : [
{boxLabel: 'A', name: 'projects', inputValue: 'A'},
{boxLabel: 'B', name: 'projects', inputValue: 'B'},
{boxLabel: 'C', name: 'projects', inputValue: 'C'},
{boxLabel: 'D', name: 'projects', inputValue: 'D'},
{boxLabel: 'E', name: 'projects', inputValue: 'E'}
]
In a normal servlet i would use
request.getParameterValues("projects") and get a String array which i can iterate.
But how should i use the formParameters map parameter of the @DirectFormPostMethod, which i guess does not allow multiple keys?!

Can you give me any hint?

Hi,

DJN does not support multi-valued keys. You will need to create your Checkboxgroup so that the checkboxes have different name, as in


id : 'projects',
fieldLabel : 'Projects',
name : 'projects',
xtype : 'checkboxgroup',
columns : 3,
allowBlank : false,
items : [
{boxLabel: 'A', name: 'projects1', inputValue: 'A'},
{boxLabel: 'B', name: 'projects2', inputValue: 'B'},
{boxLabel: 'C', name: 'projects3', inputValue: 'C'},
{boxLabel: 'D', name: 'projects4', inputValue: 'D'},
{boxLabel: 'E', name: 'projects5', inputValue: 'E'}
]
While not ideal, I think it will not be that much of a problem to implement checkbox groups this way.

An historical explanation is in order. This limitation allowed me to pass a Map<String,String> to the Java method handling the request, making for a very simple method handler. But, to be fair, if I had to implement DJN right now, I would have done it differently.

Hope this is not much of a problem.

Best regards,

Pedro.

pagullo
18 Jan 2010, 6:26 AM
So, if on the Ext side you create an ExtRequest and call Server.djn_getData, you should see the error referencing LinkedList. As I mentioned before, my code never references a LinkedList, so I think it is coming out of the GSON marshalling logic.

There are several simple workarounds to this, so I am mostly just asking about this out of curiosity and desire to understand the whole thing better. If I can clarify anything further, please let me know.

Greg,

Personally, I pass back & forth the simplest possible structures. If the business class is simple, I use it.

Else, I create a custom class that just wraps the business class in a way GSON likes, and then recreate/locate/update the real business object when my Java method receives the wrapper object.

Whether GSON creates a LinkedList or not, I just do not care: if I really truly needed a UniqueList, I would create a wrapper class with a List, and pass it back and forth.

Later, I would recreate the desired UniqueList in the method handling the request. And, that would be a good place to check whether the list really has unique values when it comes back from Javascript land...

For complex classes, trying to make them GSON-friendly and Business friendly at the same time can end up in wasting lots of time with no real added value. Making wrapper class insulates you from details. Take into account that the overhead will be very small, compared to communication time.

Just my two cents.

As always, the devil is in the details.

Regards,

jcalfee
18 Jan 2010, 10:55 AM
Has anyone tried this in AppEngine yet?

There are two things I'm wondering about:


I'm not sure exactly when DirectJNgine decides to write Api.js, but in AppEngine you can't do this at runtime. You don't have access to the filesystem in app engine. In another project I have seen the api implemented dynamically using a Servlet; I kinda though that this project would take the same approach.
You can't create your own threads in AppEngine.

pagullo
19 Jan 2010, 2:38 AM
Has anyone tried this in AppEngine yet?

There are two things I'm wondering about:


I'm not sure exactly when DirectJNgine decides to write Api.js, but in AppEngine you can't do this at runtime. You don't have access to the filesystem in app engine. In another project I have seen the api implemented dynamically using a Servlet; I kinda though that this project would take the same approach.



Hi,

The API file is written at startup time to

a) allow easy file caching,
b) save generation time and
c) be able to minify the file just once (a *very* expensive operation).

A main concern for DJN is to be as fast as possible, and this helps with that.

From what I've read in some other thread, you might be willing to implement part of the Ext.Direct Java api on your own. So, why don't you just contribute support to generate the API file outside of the web app? -and then, some configuration flag to tell DJN to bypass API file generation.

That way, you can put the generated API file in the appropriate directory when you deploy the app, instead of relying on DJN to generate it. Zero startup time + no need to access the file system sounds like a good deal :)

I think this will almost be a copy&paste thing, if you start with the servlet code. The community will be grateful if somebody makes DJN available to AppEngine users -and I'm really busy nowadays.


You can't create your own threads in AppEngine.Multithreaded batched request handling can be disabled, and it is very likely this will be the only think you need to do. Check the documentation, please.

Regards,

jcalfee
20 Jan 2010, 12:57 PM
Great, I'm glad to hear the threads are optional. That makes this change minimal.

I'm not using this at the moment, but I'll send you the patch once it is working in a project.

minneyar
20 Jan 2010, 1:23 PM
Has anybody used the Ext.us.grid.GridFilters plugin in Ext 3.1 together with a DirectStore? I'm trying to do that, but I'm having some odd problems. I've got a DirectStore and a GridPanel using it that work fine with DirectJNgine, but when I add in a GridFilters plugin (with encode set to "true" and local set to "false"), it seems to have problems parsing the JSON sent as the filter argument. According to FireBug, the JSON posted to the servlet looks like this:


{"action":"RequestHandler","method":"getData","data":["signalUpTime","DESC",0,10,"[{\"type\":\"date\",\"comparison\":\"eq\",\"value\":\"01/12/2010\",\"field\":\"requestTime\"}]"],"type":"rpc","tid":1023}But when using DirectJNgine 1.0, I get exceptions in Tomcat's log that look like this:


Wed Jan 20 2010 20:14:30:282 - [ERROR] JsonRequestProcessor -rid: 1023- (Controlled) server error: Failed parsing JSON source: java.io.StringReader@5d282c43 to Json for Method 'RequestHandler.getData'
com.google.gson.JsonParseException: Failed parsing JSON source: java.io.StringReader@5d282c43 to Json
at com.google.gson.JsonParser.parse(JsonParser.java:57)
at com.google.gson.JsonParser.parse(JsonParser.java:39)
at com.softwarementors.extjs.djn.router.processor.standard.json.JsonRequestProcessor.getIndividualRequestJsonParameters(JsonRequestProcessor.java:286)
at com.softwarementors.extjs.djn.router.processor.standard.json.JsonRequestProcessor.checkJsonMethodParameterTypes(JsonRequestProcessor.java:306)
at com.softwarementors.extjs.djn.router.processor.standard.json.JsonRequestProcessor.getIndividualRequestParameters(JsonRequestProcessor.java:223)
at com.softwarementors.extjs.djn.router.processor.standard.json.JsonRequestProcessor.processIndividualRequest(JsonRequestProcessor.java:365)
at com.softwarementors.extjs.djn.router.processor.standard.json.JsonRequestProcessor.processIndividualRequestsInThisThread(JsonRequestProcessor.java:127)
at com.softwarementors.extjs.djn.router.processor.standard.json.JsonRequestProcessor.process(JsonRequestProcessor.java:109)
at com.softwarementors.extjs.djn.router.RequestRouter.processJsonRequest(RequestRouter.java:77)
at com.softwarementors.extjs.djn.servlet.DirectJNgineServlet.doPost(DirectJNgineServlet.java:377)
at java.lang.Thread.run(Thread.java:619)
Caused by: com.google.gson.ParseException: Encountered "type" at line 1, column 33. Was expecting one of: "," ...
"]" ...
at com.google.gson.JsonParserJavacc.generateParseException(JsonParserJavacc.java:658)
at com.google.gson.JsonParserJavacc.jj_consume_token(JsonParserJavacc.java:540)
at com.google.gson.JsonParserJavacc.JsonArray(JsonParserJavacc.java:134)
at com.google.gson.JsonParserJavacc.parse(JsonParserJavacc.java:22)
at com.google.gson.JsonParser.parse(JsonParser.java:53)
... 33 moreI'm guessing that somehow, the "]" on the end of the filters parameter is getting lost. My suspicion is reinforced when I test it against the current DirectJNgine 1.2 beta; it doesn't throw an exception, and the function gets called, by the string passed in to the "filters" argument looks like this when I print it out:


[{"type":"date","comparison":"eq","value":"01/12/2010","field":"requestTime"}Any idea what's going wrong? I can manually add a "]" to the end of the string and then parse it, but that's quite a kludge...

pagullo
20 Jan 2010, 11:18 PM
Great, I'm glad to hear the threads are optional. That makes this change minimal.

I'm not using this at the moment, but I'll send you the patch once it is working in a project.

Great!

Right now I'm making DJN 1.2 beta 1 available: you will probably want to use this beta as the starting point to add this functionality.

You can download it from http://code.google.com/p/directjngine/

Best regards,

pagullo
21 Jan 2010, 12:02 AM
Today I am releasing DJN 1.2 beta 1. You can download it from http://code.google.com/p/directjngine/.

Here is a list of what's new and improved.

For detailed info, check the User's Guide, which has been updated and has new chapters devoted to the new functionality.


New in DJN 1.2: Support for stateful actions
It is possible to have session and application scoped actions, that will remember their state between requests.

To make an action stateful, use the @ActionScope annotation.

Take a look at the new chapter in the User's Guide to get more information about stateful actions.

Sample code:


@ActionScope(scope=Scope.SESSION)
public class SessionStatefulActionTest {
int count;
String value;
// ...
}Once the SessionStatefulActionTest action is declared to be session scoped, it will be stored in the user session: this means that its count and value fields will be remembered across request belonging to the same user session.


New in DJN 1.2: Support for accessing the current session, etc. from within action methods
Now it is possible to get access to the current session, servlet context, servlet configuration, etc., from within action methods.
To do that, just use the new WebContext and WebContextManager classes.

Take a look at the new chapter in the User's Guide to get more information about WebContext.

Sample code:


@DirectMethod
public WebContextInfo test_webContext() {
WebContext context = WebContextManager.get();
HttpSession session = context.getSession();
ServletContext application = context.getServletContext();

// Keep a counter of how many times we have called this method
// in this session
Integer callsInSession=(Integer)session.getAttribute("callsInSession");
if( callsInSession == null ) {
callsInSession = new Integer(0);
}
callsInSession = new Integer(callsInSession.intValue() + 1);
session.setAttribute("callsInSession", callsInSession);

// ...
}You will probably find that using session/application scoped actions might be an easier way to accomplish your goals, though.


New in DJN 1.2: Support for multiple action instances
Now that actions can be stateful, it makes sense to have more than one action instance for a given Java class, each instance manging its own state.

Other additions/improvements
· All bugs reported against DJN 1.1 have been fixed.

· We have added more tests, mostly to ensure bug fixes work: we have 100 hundred automated tests nowadays.

· We have moved to ExtJs 3.1 for testing to ensure that we remain up to date.

· Licensing has been "fixed": we are LGPL v3 -the way it was intended to be from the beginning.


Code breaking changes
· The programmatic API has been modified so that poll methods belong to actions, instead of being global. This was a must to support stateful actions.

· The suggested workaround for handling "\n" and "\r" characters in DJN 1.1 does not work anymore: instead you should pass them "as-is".


Tested browsers
· Internet Explorer 8: 8.0.6001.18702

· Firefox 3.5.3

· Safari 4.0 (530.17)

· Google Chrome 3.0.195.53

· Opera 9.64.


Other issues
· Testing: the automated 'test_getSessionData' test fails sometimes. This is due to difficult to fix test timing issues.
If you execute the test method several times, the false error will probably not appear again.
We intend to fix this for the final DJN release.

· Integration with Ext JS Designer is planned, but this will depend on the ExtJS Designer release date.


Intent of this release
The first goal of this release is to expose the new support for state handling via stateful actions and WebContext. I consider that API to be closed -unless you find a big problem.

The second goal is to get feedback on enhancements in DJN that will help people creating DJN extensions (Spring support by vlagorce comes to mind).

I had to change several APIs to support cleaner extension: while I think moving existing extensions to 1.2 will be very easy, I wanted to provide this beta in order to get feedback and help to port extensions to 1.2 before the final release. My current plan is to release DJN 1.2 final in about two weeks: I hope this is time enough for you to check whether the internal API changes are ok with you.


To all, thank you for your encouragement and criticism: I hope this new release of DJN helps you make bettter software.

Best regards.

minneyar
25 Jan 2010, 2:54 PM
After further investigation, I discovered that the 1.2 beta was truncating the last character of all of my strings. I'm not sure if I'm the only person who's experienced the problem, but every single string I sent through Ext.Direct to a DirectJNgine servlet was missing the last character when I printed it out, even on calls that weren't trying to use the grid filtering at all.

I decided to give version 1.1 a try, and I got the same exception as I did when using version 1.0. I tried turning debugging all the way up and adding in a few log statements of my own to DirectJNgine's code, and as far as I can tell, the issue is that Gson is having problems parsing a JSON string that contains an escaped JSON string inside it, not that DirectJNgine is doing anything wrong. :-(

I've got a working solution, but I ended up modifying the code in the GridFilters plugin; the "normal" behavior is that if the "encode" flag is set to true, it will convert the object to a JSON string and add that to the parameters for the POST request, and if "encode" is false, it will flatten the object into a series of parameters and add them all to the request. I modified the code in my GridFilters plugin so that if "encode" is false, it will instead just copy the filters object into the parameters, which then gets turned into JSON with the rest of the object when the request is submitted. I then made a custom Gson parser to turn that object into a Java class. This seems to work fine.

pagullo
26 Jan 2010, 2:42 AM
After further investigation, I discovered that the 1.2 beta was truncating the last character of all of my strings. I'm not sure if I'm the only person who's experienced the problem, but every single string I sent through Ext.Direct to a DirectJNgine servlet was missing the last character when I printed it out, even on calls that weren't trying to use the grid filtering at all.

I decided to give version 1.1 a try, and I got the same exception as I did when using version 1.0. I tried turning debugging all the way up and adding in a few log statements of my own to DirectJNgine's code, and as far as I can tell, the issue is that Gson is having problems parsing a JSON string that contains an escaped JSON string inside it, not that DirectJNgine is doing anything wrong. :-(

I've got a working solution, but I ended up modifying the code in the GridFilters plugin; the "normal" behavior is that if the "encode" flag is set to true, it will convert the object to a JSON string and add that to the parameters for the POST request, and if "encode" is false, it will flatten the object into a series of parameters and add them all to the request. I modified the code in my GridFilters plugin so that if "encode" is false, it will instead just copy the filters object into the parameters, which then gets turned into JSON with the rest of the object when the request is submitted. I then made a custom Gson parser to turn that object into a Java class. This seems to work fine.

Truncating the last character in all strings? Really weird!

If you provide me with a minimal project that systematically shows this behavior, I will take a look at it. You are talking about "escaped" JSON strings, can you provide me with a pair of strings highlighting the problem?

Just in case, did you check the GSON forums/mailing lists/whatever they have? It might be some known issue.

Thanks for reporting the issue

minneyar
26 Jan 2010, 8:50 AM
If you provide me with a minimal project that systematically shows this behavior, I will take a look at it.

Sure, I can do that. I don't really want to post a whole WAR file since including all the libraries will make it rather large, but I'll paste the pertinent source code here.

The test class here just has a single DirectMethod function that accepts a String, logs it, and then returns that same String. testpage.html creates an Ext.Window that has two buttons; one sends the string "testing" to TestClass and then appends the return value to the window, and the second one creates an object, uses Ext to transform it into JSON, and sends that to TestClass.

With DirectJNgine 1.1, the first button echoes back "testing", and the second button causes Tomcat to throw a JsonParseException. With 1.2.beta_1, the first button echoes back "testin", and the second button echoes back the expected JSON string, except it's missing a "}" on the end.

For what it's worth, this is running on Tomcat 6.0.20 on a Red Hat Enterprise Linux 5.3 server. I don't think it would make a difference, but we have a number of other libraries in our Tomcat's lib dir, including Sun's thin JDBC driver, Log4j 1.2.15, Xerces, JacORB 2.3.1, SLF4J, and a few custom libs, as well as all of DirectJNgine's requirements.

testpage.html:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />

<link href="lib/ext/resources/css/ext-all.css" rel="stylesheet" type="text/css" />

<title>Test Page</title>

<script language="JavaScript1.5" type="text/javascript" src="lib/prototype/prototype.js"></script>
<script language="JavaScript1.5" type="text/javascript" src="lib/scriptaculous/scriptaculous.js"></script>
<script language="JavaScript1.5" type="text/javascript" src="lib/ext/adapter/prototype/ext-prototype-adapter-debug.js"></script>
<script language="JavaScript1.5" type="text/javascript" src="lib/ext/ext-all-debug.js"></script>
<!-- This file is automatically generated by DirectJNgine, based on
config parameters in the web.xml file. -->
<script language="JavaScript1.5" type="text/javascript" src="direct/Api.js"></script>

<script language="JavaScript1.5" type="text/javascript">
var win = null;
Ext.Direct.addProvider(Ext.app.REMOTING_API);
window.onload = function addTestButton() {

/** Setting for Ext JS to locate black gif used by widgets */
Ext.BLANK_IMAGE_URL = "lib/ext/resources/images/default/s.gif";
Ext.SSL_SECURE_URL = "lib/ext/resources/images/default/s.gif";

Ext.onReady(function() {
Ext.QuickTips.init();
var qt = Ext.QuickTips.getQuickTip();
qt.interceptTitles = true;
});

win = new Ext.Window({
title: 'Test Window',
items: [
{
xtype: 'button',
text: 'Truncation test',
handler: function() {
TestClass.doStuff( "testing", function(response) {
win.add(new Ext.Panel({html: response}));
win.doLayout();
win.syncShadow();
});
}
}, {
xtype: 'button',
text: 'Embedded JSON test',
handler: function() {
var thing = {
one: 'hello',
two: ['first', 'second', 'third'],
three: {
anotherThing: 'four'
}
};
TestClass.doStuff( Ext.util.JSON.encode(thing), function(response) {
win.add(new Ext.Panel({html: response === undefined ? "undefined" : response}));
win.doLayout();
win.syncShadow();
});
}
}

]
});
win.show();
};
</script>
</head>
<body>
</body>
</html>
org.test.TestClass.java:

package org.test;

import org.apache.log4j.Logger;

import com.softwarementors.extjs.djn.config.annotations.DirectMethod;

public class TestClass
{
private static final Logger logger = Logger.getLogger( TestClass.class );
@DirectMethod
public static String doStuff(String testString) {
logger.info( "Got:\n" + testString );

return testString;
}
}
web.xml:

<!DOCTYPE web-app PUBLIC
'-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
'http://java.sun.com/dtd/web-app_2_3.dtd'>
<web-app>

<display-name>Test</display-name>

<description>
Just testing.
</description>

<servlet>
<servlet-name>DjnServlet</servlet-name>
<servlet-class>com.softwarementors.extjs.djn.servlet.DirectJNgineServlet</servlet-class>
<init-param>
<param-name>providersUrl</param-name>
<param-value>djn/directprovider</param-value>
</init-param>
<init-param>
<param-name>apis</param-name>
<param-value>direct</param-value>
</init-param>
<init-param>
<param-name>direct.apiFile</param-name>
<param-value>direct/Api.js</param-value>
</init-param>
<init-param>
<param-name>direct.apiNamespace</param-name>
<param-value>Ext.app</param-value>
</init-param>
<init-param>
<param-name>batchRequestsMultithreadingEnabled</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>direct.classes</param-name>
<param-value>
org.test.TestClass
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>DjnServlet</servlet-name>
<url-pattern>/djn/directprovider/*</url-pattern>
</servlet-mapping>

</web-app>

Sesshomurai
30 Jan 2010, 6:19 AM
Hi,
I am converting to Direct using this nice package. I have some grid stores that use dynamic parameters to load the grid. So, for this, I need to use paramsAsHash=true, but for some reason DirectJNgine says it cannot use this setting with DirectStore calls.

is this true? Why? And how can I do this otherwise?

thank you for any tips!

Sesshomurai
30 Jan 2010, 9:07 AM
There also appears to be a bug in 1.2 beta where if I try to send a basic string parameter that is long, the JSON conversion fails.



JsonException: Failed attempt to convert from a json string to java method parameters. Method='GridwaveList.getList', Json string='["symphony","jsonname='properties' and jsoncount='numProperties' and ablablablablablablabla"]', ExpectedTypes='java.lang.String, java.lang.String'


If I shorten my second parameter a few characters, it works.

EDIT: I traced this problem to the class JsonRequestProcessor.java around line 305.



if( isString(jsonValue) ) { // Just because of '\n' or '\r', which were decoded previously, so we need to re-encode them
json = reEncode(jsonValue.toString());
}


The reEncode wasn't working well in many cases.

Also, I found that DirectJNgine 1.2 beta does not work with Ext 3.1 release. It complains that all parameters are undefined. However, it worked fine with ExtJS 3.1.1-beta (which my app doesn't yet work with).

Will DirectJNgine 1.2 release work with ExtJS 3.1 release?

thanks

pagullo
31 Jan 2010, 8:34 AM
Hi,
I am converting to Direct using this nice package. I have some grid stores that use dynamic parameters to load the grid. So, for this, I need to use paramsAsHash=true, but for some reason DirectJNgine says it cannot use this setting with DirectStore calls.

is this true? Why? And how can I do this otherwise?

thank you for any tips!

Of course, you can do that: you just need to implement a JSON handling method whenever you don't know the parameter names in advance.

Check the User's Guide, chapter "Handling JSON data directly".

Regards,

pagullo
31 Jan 2010, 10:29 AM
With DirectJNgine 1.1, the first button echoes back "testing", and the second button causes Tomcat to throw a JsonParseException. With 1.2.beta_1, the first button echoes back "testin", and the second button echoes back the expected JSON string, except it's missing a "}" on the end.



Thanks for the detailed report!

First of all, I have moved your test to my test environment, making it minimal. I am using DJN 1.2 beta 1 and ExtJs 3.1.0 (which is the supported version for 1.2).

1) Regarding the "Truncation test", things seem to work for me. The Java code receives the "testing" string, returns it, and then Javascript receives it correctly too.

My test environment does not include scriptaculous, prototype, etc.

Instead of this code in your original HTML page,



<script language="JavaScript1.5" type="text/javascript" src="lib/prototype/prototype.js"></script>
<script language="JavaScript1.5" type="text/javascript" src="lib/scriptaculous/scriptaculous.js"></script>
<script language="JavaScript1.5" type="text/javascript" src="lib/ext/adapter/prototype/ext-prototype-adapter-debug.js"></script>
<script language="JavaScript1.5" type="text/javascript" src="lib/ext/ext-all-debug.js"></script>
<script language="JavaScript1.5" type="text/javascript" src="direct/Api.js"></script>

I use this


<script type="text/javascript" src="../extjs/adapter/ext/ext-base-debug.js"></script> <!-- +PAG -->
This smells a lot like there is some trouble when using prototype (i.e., ext-prototype-adapter-debug.js instead of ext-base-debug.js).

Can you check whether things work for you when you use ext-base-debug.js? Please, make sure you use ExtJs 3.1.0 too, as this is the supported version for DJN 1.2 beta 1, and it might be getting in the way.

2) When it comes to the "Embedded JSON test", I think we should try to nail down the first problem, and then check this second issue again -maybe they are related, maybe not.

Don't know whether what follows will be useful to you...
With my test config, if you change your JS code to this:


// Note I am not json-encoding 'thing' explicitly, just passing it directly to the function)
TestClass.doStuff2( thing, function(response) {
win.add(new Ext.Panel({html: response === undefined ? "undefined" : response}));
win.doLayout();
win.syncShadow();
});
writing the Java doStuff2 method as follows works:


//... Other code in TestClass...
//...

public static class Thing {
public String one;
public String[] two;
public static class MyThreeClass {
public String anotherThing;
}
public MyThreeClass three;
}

@DirectMethod
public static String doStuff2( Thing thing ) {
assert thing != null;
assert thing.one.equals( "hello");
assert thing.two != null;
assert thing.two.length == 3;
assert thing.two[0].equals( "first");
assert thing.two[1].equals( "second");
assert thing.two[2].equals( "third");
assert thing.three != null;
assert thing.three.anotherThing.equals( "four");

return "ok";
}

But maybe you already knew this and what you really, really want to do is pass *that* string...

Please, let me know what happens.

pagullo
31 Jan 2010, 10:46 AM
Thanks for the detailed report!


There also appears to be a bug in 1.2 beta where if I try to send a basic string parameter that is long, the JSON conversion fails.


I am investigating this 'long string' issue.



Also, I found that DirectJNgine 1.2 beta does not work with Ext 3.1 release. It complains that all parameters are undefined. However, it worked fine with ExtJS 3.1.1-beta (which my app doesn't yet work with).
I use ExtJs 3.1.0 to run all DirectJNgine automated test for DJN 1.2, as it will be the supported version.

I might be turning paranoid, because I have ext-all.js & ext-all-debug.js open in front of me right now. I am using 3.1.0, believe me :)

Can you double-check this, please?

Regards,

Sesshomurai
31 Jan 2010, 1:19 PM
Hi,
I will do some more thorough tests and report back. Thanks for a great package by the way.

I re-downloaded 3.1 clean and put it in my app where the previous 3.1.1-beta was and I get this error in FireBug:



uncaught exception: Direct call error, 'GridwaveObject.getProperties' must not receive undefined parameters. Call parameters: [undefined,undefined,undefined,undefined,undefined]
[Break on this error] Ext.DomHelper=function(){var t=null,k=...lclick",this.onNodeDblClick,this)}});


If I move 3.1.1 in its place, it executes fine. I set the store.baseParams in the 'beforeload' event on a DirectStore point to my API. I checked the values of the baseParams and they are fine, so not sure why the call isn't validating.

pagullo
31 Jan 2010, 11:24 PM
Other things you might try:

1) If you are using the existing support for checking client-side parameter checking, remove it: check the User's Guide for details. Should make no difference, but...

2) Create the smallest html/js/java/web.xml code that shows this behavior for ExtJs 3.1.0 + DJN 1.2 beta 1, and post it here. Try to add the code to the enclosed djn_test app and execute it: that way I will be able to reproduce it in the same environment, avoiding subtle config problems.

minneyar
1 Feb 2010, 8:37 AM
Ok, I've done some more testing and I think I've figured a few things out...

1) I'm already using Ext 3.1.0. I tried removing prototype/scriptaculous and just using ext-base, but I had the same problem.

2) Making a class for the "Thing" object worked properly. The reason why I needed to manually encode the JSON string and pass it in is because that's how the official GridFilters plugin encodes its "filters" parameters and inserts them into the request. I modified my copy of the GridFilters plugin to pass the object in without manually encoding it, so it's not really an issue for me now.

Based on my Firebug console, I can see that the right strings are getting posted to the servlet, so the problems are definitely somewhere in the Java code. I went digging through DirectJNgine to find out what's happening, and I think the problem is in JsonRequestProcessor.java. Here's the original code:


private String reEncode( String jsonString ) {
String json = getGson().toJson(jsonString);
json = json.substring(2, json.length()-4) + "\"";
return json;
}I'm not really sure what this function is trying to do; it seems like it's removing the escaped quotation marks around the string, but a comment in the getMethodParameters function makes it also seem like it's doing something to newline characters in the string. I'm guessing this problem is happening to me but not you because I'm using Linux on my client and server machines and you're using Windows somewhere; Linux just uses the "LF" character for its newline, but Windows uses "CR+LF", so the Windows version of the same string will have an extra character in it.

I modified the reEncode function to look like this:


private String reEncode( String jsonString ) {
final Pattern p = Pattern.compile("^\\\"\\\\\\\"(.*)\\\\\\\"\\\"$");
String json = getGson().toJson(jsonString);
Matcher m = p.matcher( json.trim() );
if( m.matches() ) {
json = "\"" + m.group(1).trim() + "\"";
}
else {
logger.error( "No match found; this shouldn't happen." );
}
return json;
}I don't know if that's how you intended for the function to behave, but that causes every test to pass for me.

pagullo
1 Feb 2010, 11:33 PM
I fixed the problem with the re-encoded string too.

It happened because GSON might pretty-print strings for output when it considers they are "long enough", adding a '\n' I never expected: this caused the string to be an illegal JSON string, and GSON to complain when it processes the string again.

The test for long strings is now test #101 :)

With respect to the first issue, I just can't reproduce it, and know of nobody else who is suffering it: it is a big issue, so I'm sure if somebody else had experienced it, he would have reported it.

So, the only possibility I can think of is for you to reproduce the problem in a new page that is part of the djn_test application, so that I can reproduce it making sure we have the same configuration.

Best regards,

pagullo
2 Feb 2010, 12:25 AM
There also appears to be a bug in 1.2 beta where if I try to send a basic string parameter that is long, the JSON conversion fails.


This is fixed now, and will make into the next release. The JSON encoding problem mentioned in some posts by minneyar is in reality a manifestation of the same problem.

The new beta 2 contains a fix for this: you can download it from http://code.google.com/p/directjngine/

Thanks to you and minneyar for the detailed report and suggestions.

pagullo
2 Feb 2010, 1:16 AM
I am releasing DirectJNgine 1.2 beta 2, which solves all known issues with 1.2 beta 1.

As always, you can download it from http://code.google.com/p/directjngine/. The download just contains jars for classes and source code.

The User's Guide hasn't changed: just download the User's Guide for beta 1.

Best regards.

minneyar
2 Feb 2010, 6:27 AM
Beta 2 seems to be working fine for me. Thanks!

minneyar
2 Feb 2010, 7:33 AM
Wait, I take that back... I didn't realize that I was accidentally running my test against the old jar file.

Unfortunately, beta 2 still has the same issue for me, where the last character of strings is truncated. :-(

Sesshomurai
2 Feb 2010, 6:30 PM
pagullo,
Kudos to you for the fixes.

As for my other issue with the undefined parameters, I think it may actually be a problem with Ext.Direct and I will inquire over there. But basically, what I am seeing is that if I use a DirectProxy function call in a Ext.data.Store, and in my beforeload: event handler, I attempt to modify (legally) the store.baseParams, the modified values DO NOT make it into the method call, thus leaving them undefined. This is unexpected behavior that MAY have been fixed in 3.1.1. but that is a guess on my part.

Anyone from ExtJS can comment on whether this is correct behavior?

pagullo
2 Feb 2010, 11:46 PM
Unfortunately, beta 2 still has the same issue for me, where the last character of strings is truncated. :-(

Too bad. I haven't found a way to reproduce the problem you are experiencing, so unfortunately this was to be expected.

I really really need you submit something I can reproduce before I can take a look at this to check whether this is a DJN issue and solve it -much better if it is part of the djn_test app, to ensure configurations are exactly the same, as your issue is really elusive.

Regards

sayonara
3 Feb 2010, 1:09 AM
Hi There! Long time lurker, first time poster.

minneyar, just so you don't feel like you're going crazy, I have the same issue as you. All the strings that are processed by DirectJNgine have the last character chopped off them. I don't know what the exact reason for this is, but it seems to be the "reEncodeToJson" method in "JsonRequestProcessor" that's doing it. I've only just started looking at DirectJNgine in the past few hours, so I don't know what that method's trying to do exactly, but I replaced it with something like this, and that seems to be working OK;

private String reEncodeToJson( String jsonString ) {

final String DELIMITER = "\\\"";
final int DELIMITER_LENGTH = DELIMITER.length();

String json = getGson().toJson(jsonString);

int start = json.indexOf(DELIMITER);
int end = json.lastIndexOf(DELIMITER);

String result2 = json;
if(start > -1 && end > start) {
return "\"" + json.substring(start + DELIMITER_LENGTH,end) + "\"";
}
else {
return json;
}
}Also, if anyone's interested, I modified the CodeFileGenerator (and the DirectJNgineServlet, slightly) so that it doesn't write the API definitions to an actual file but buffers them in memory and serves them if you issue a GET to "djn/directprovider" and pass a parameter specifying the API you want the details for. For example;

<script type="text/javascript" src="djn/directprovider?api=demo"></script>This means it (kind of) works with GAE. There seems to be an issue with persisting objects from within Action classes, but I'm not sure that it's actually DirectJNgine that's causing that issue.

Cheers.

pagullo
3 Feb 2010, 2:06 AM
minneyar, just so you don't feel like you're going crazy, I have the same issue as you. All the strings that are processed by DirectJNgine have the last character chopped off them.


Would be great if you could post the Java/js/web.xml code here!

...

Besides, could you try the following modificationts to JsonRequestProcessor.java and tell me what happens?

1) Modify reEncodeToJson as follows:


private String reEncodeToJson( String jsonString ) {
String json = getGson().toJson(jsonString);
return json.trim();
}2) Modify the line calling reEncodeToJson as follows:



// ...
json = reEncodeToJson(jsonValue.getAsString());instead of


json = reEncodeToJson(jsonValue.toString());Let me know what happens.

Regards,

sayonara
3 Feb 2010, 3:49 AM
The js is just a simple Ext JS form. The remote Java method is called "manually" from a button handler, it just gathers up the data and calls the remote method directly. I can see in Firebug that the data is sent correctly in the POST request. The Java method is similar to the test method from the DirectJNgine docs, it just takes three String parameters and returns them concatenated together.

But, whatever, those changes you suggested worked perfectly. So thanks for that!

Cheers.

Sesshomurai
3 Feb 2010, 9:23 AM
pagullo,
Kudos to you for the fixes.

As for my other issue with the undefined parameters, I think it may actually be a problem with Ext.Direct and I will inquire over there. But basically, what I am seeing is that if I use a DirectProxy function call in a Ext.data.Store, and in my beforeload: event handler, I attempt to modify (legally) the store.baseParams, the modified values DO NOT make it into the method call, thus leaving them undefined. This is unexpected behavior that MAY have been fixed in 3.1.1. but that is a guess on my part.

Anyone from ExtJS can comment on whether this is correct behavior?

pagullo, you are off the hook. This is a bug in 3.1 that was fixed in 3.1.1
http://www.extjs.com/forum/showthread.php?t=88273

minneyar
3 Feb 2010, 12:57 PM
It happens to me for every string -- I can't make any tests that don't have this problem. Maybe it's some kind of difference in operating environment? Are your clients/server running Windows rather than Linux?

If I make the changes you suggested to JsonRequestProcessor.java, everything seem to work perfectly.

zaqwsxqwer
4 Feb 2010, 5:42 PM
I have got the same "the last character of string has lost" problem, when I debug the source code:
private String reEncodeToJson( String jsonString ) {
final int DELIMITER_LENGTH = "\\\"".length();
final char FIRST_DELIMITER_CHAR = '\"';

// Unfortunately, gson 1.3 might pretty-print strings, adding '\n' or other
// special characters at beginning of long strings. Need to get past them...
String json = getGson().toJson(jsonString);
int firstChar = DELIMITER_LENGTH;
for( int i = 0; i < json.length(); i++) {
char c = json.charAt(i);
if( c == FIRST_DELIMITER_CHAR) {
firstChar += i;
break;
}
}

// We remove the beginning and ending JSON-delimiters, as the string value is
// what is delimited by them.
String result2 = json.substring(firstChar, json.length()-(2*DELIMITER_LENGTH)) + "\"";//the code raise up the problem
return result2;
}

zaqwsxqwer
4 Feb 2010, 5:56 PM
1.1 is ok, parameter string is ok.

pagullo
4 Feb 2010, 11:21 PM
It happens to me for every string -- I can't make any tests that don't have this problem. Maybe it's some kind of difference in operating environment? Are your clients/server running Windows rather than Linux?

If I make the changes you suggested to JsonRequestProcessor.java, everything seem to work perfectly.

I'm running Windows. I suspect some issue with writers using different characters for a new line for Windows and Linux...

Anyway, since the proposed code passes all tests for me and seems to work for those having this problem, I will use it in the next release.

I hope this solves the issue.

pagullo
4 Feb 2010, 11:50 PM
Today we are releasing DirectJNgine 1.2 beta 3.

The only change to this beta is a proposed fix to the issue some users were experiencing with strings being stripped of their last character.

You can download it from http://code.google.com/p/directjngine/.

To all beta testers, thanks for your feedback!

pagullo
4 Feb 2010, 11:52 PM
I have got the same "the last character of string has lost" problem...


Please, check DJN 1.2 beta 3 and let me know if it works for you.

Sesshomurai
5 Feb 2010, 5:45 AM
I think the long string bug is still there or a related problem. With beta 3 I get this using a long string.



JsonException: Failed attempt to convert from a json string to java method parameters. Method='GridwaveSymphony.getFiles', Json string='["symphony"," select * from `scrapbucketout` where parent='beb8596a-1dc0-4e61-9297-3267ab5d1528' and type='file'",5,5,"rO0ABXNyACdjb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5Nb3JlVG9rZW7racXLnINNqwMA C0kAFGluaXRpYWxDb25qdW5jdEluZGV4WgAOaXNQYWdlQm91bmRhcnlKAAxsYXN0RW50aXR5SURa AApscnFFbmFibGVkSQAPcXVlcnlDb21wbGV4aXR5SgATcXVlcnlTdHJpbmdDaGVja3N1bUkACnVu aW9uSW5kZXhaAA11c2VRdWVyeUluZGV4TAANY29uc2lzdGVudExTTnQAEkxqYXZhL2xhbmcvU3Ry aW5nO0wAEmxhc3RBdHRyaWJ1dGVWYWx1ZXEAfgABTAAJc29ydE9yZGVydAAvTGNvbS9hbWF6b24v c2RzL1F1ZXJ5UHJvY2Vzc29yL1F1ZXJ5JFNvcnRPcmRlcjt4cAAAAAQATw0PyGR0wAAAAAAAAQAA AACnEObjAAAAAAFwdAAkYmViODU5NmEtMWRjMC00ZTYxLTkyOTctMzI2N2FiNWQxNTI4fnIALWNv bS5hbWF6b24uc2RzLlF1ZXJ5UHJvY2Vzc29yLlF1ZXJ5JFNvcnRPcmRlcgAAAAAAAAAAEgAAeHIA DmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQACUFTQ0VORElOR3g="]', ExpectedTypes='java.lang.String, java.lang.String, int, int, java.lang.String'


It should be valid I think. I will debug directjengine further for clues.

minneyar
5 Feb 2010, 6:22 AM
Beta 3 works great for me. Thanks!

pagullo
5 Feb 2010, 8:02 AM
I think the long string bug is still there or a related problem. With beta 3 I get this using a long string.



JsonException: Failed attempt to convert from a json string to java method parameters. Method='GridwaveSymphony.getFiles', Json string='["symphony"," select * from `scrapbucketout` where parent='beb8596a-1dc0-4e61-9297-3267ab5d1528' and type='file'",5,5,"rO0ABXNyACdjb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5Nb3JlVG9rZW7racXLnINNqwMA C0kAFGluaXRpYWxDb25qdW5jdEluZGV4WgAOaXNQYWdlQm91bmRhcnlKAAxsYXN0RW50aXR5SURa AApscnFFbmFibGVkSQAPcXVlcnlDb21wbGV4aXR5SgATcXVlcnlTdHJpbmdDaGVja3N1bUkACnVu aW9uSW5kZXhaAA11c2VRdWVyeUluZGV4TAANY29uc2lzdGVudExTTnQAEkxqYXZhL2xhbmcvU3Ry aW5nO0wAEmxhc3RBdHRyaWJ1dGVWYWx1ZXEAfgABTAAJc29ydE9yZGVydAAvTGNvbS9hbWF6b24v c2RzL1F1ZXJ5UHJvY2Vzc29yL1F1ZXJ5JFNvcnRPcmRlcjt4cAAAAAQATw0PyGR0wAAAAAAAAQAA AACnEObjAAAAAAFwdAAkYmViODU5NmEtMWRjMC00ZTYxLTkyOTctMzI2N2FiNWQxNTI4fnIALWNv bS5hbWF6b24uc2RzLlF1ZXJ5UHJvY2Vzc29yLlF1ZXJ5JFNvcnRPcmRlcgAAAAAAAAAAEgAAeHIA DmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQACUFTQ0VORElOR3g="]', ExpectedTypes='java.lang.String, java.lang.String, int, int, java.lang.String'
It should be valid I think. I will debug directjengine further for clues.

Yeah, I don't see anything wrong with your parameters. In fact I have added an automated test receiving those same parameters: it passes with flying colours. I never thought passing a test would make me complain... Arrgh!

So maybe this is some system difference, maybe due to you using Linux, and me Windows.

...

Some ideas/food for thought...

Please, post both

a) The exact string reEncodeToJson receives for the last parameter (the very long string). Please, set '\' and '\r' to dark blue + bold when posting, so I can distinguish when there is a '\' or '\n' from the case where the forum software cuts the line just because it does not fit: it is very likely we are having problems with special characters, I don't want to miss any.

b) The value the local json variable takes inside of reEncodeToJson, for that parameter.

You should be looking for extraneous characters before/after the *correct* string, which should be the one you see in the log plus an starting and an ending double quote.

All we need to do in reEncodeToJson is remove all characters before/after the starting and ending double quotes: maybe there is some character that trim does not remove?

...

Last, but not least, you might want to try this version of getMethodParameters in JsonRequestProcessor, which just removes reEncodeToJson. Please, test this against all problematic cases you have found so far AND the djn_test webapp: we are in a slippery terrain, as I just can't see any of those crazy issues. If this code works, I need you pass those tests just to make sure the community does not get affected by another crazy side effect...Thanks!


private Object[] getMethodParameters(Class<?>[] parameterTypes,
JsonElement[] jsonParameters)
{
assert parameterTypes != null;
assert jsonParameters != null;

Object[] result = new Object[jsonParameters.length];
for( int i = 0; i < jsonParameters.length; i++ ) {
JsonElement jsonValue = jsonParameters[i];
Class<?> parameterType = parameterTypes[i];
Object value = null;
if( isString(jsonValue)) {
if( parameterType.equals(String.class)) {
value = jsonValue.getAsString();
}
else if(parameterType == char.class || parameterType == Character.class) {
value = new Character(jsonValue.getAsString().charAt(0));
}
else {
String json = jsonValue.toString();
value = getGson().fromJson(json, parameterType);
}
}
else {
String json = jsonValue.toString();
value = getGson().fromJson(json, parameterType);
}
result[i] = value;
}
return result;
}

...

By the way, are you using request batching? Try everything with batching on and off, please, and tell me what happens.

...

Besides, I'm looking for *whatever* might differ: O.S., library versions (are you using exactly the same JARs I use?, ExtJs version (I use 3.1.0), etc.

...

@sayonara & minneyar: you would really do me a favor if you could check whether those parameters are problematic to you, as it seems you all shared this problem in prior DJN beta.

Here is the Js code:



var param1 = "symphony";
var param2 =
" select * from `scrapbucketout` where parent='beb8596a-1dc0-4e61-9297-3267ab5d1528' and type='file'";
var param3 = 5;
var param4 = 5;
var param5 = "rO0ABXNyACdjb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5Nb3JlVG9rZW7racXLnINNqwMA C0kAFGluaXRpYWxDb25qdW5jdEluZGV4WgAOaXNQYWdlQm91bmRhcnlKAAxsYXN0RW50aXR5SURa AApscnFFbmFibGVkSQAPcXVlcnlDb21wbGV4aXR5SgATcXVlcnlTdHJpbmdDaGVja3N1bUkACnVu aW9uSW5kZXhaAA11c2VRdWVyeUluZGV4TAANY29uc2lzdGVudExTTnQAEkxqYXZhL2xhbmcvU3Ry aW5nO0wAEmxhc3RBdHRyaWJ1dGVWYWx1ZXEAfgABTAAJc29ydE9yZGVydAAvTGNvbS9hbWF6b24v c2RzL1F1ZXJ5UHJvY2Vzc29yL1F1ZXJ5JFNvcnRPcmRlcjt4cAAAAAQATw0PyGR0wAAAAAAAAQAA AACnEObjAAAAAAFwdAAkYmViODU5NmEtMWRjMC00ZTYxLTkyOTctMzI2N2FiNWQxNTI4fnIALWNv bS5hbWF6b24uc2RzLlF1ZXJ5UHJvY2Vzc29yLlF1ZXJ5JFNvcnRPcmRlcgAAAAAAAAAAEgAAeHIA DmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQACUFTQ0VORElOR3g=";
ServerMethodParametersReceptionTest.test_serverProblematicLongString2(
param1, param2, param3, param4, param5, function(provider, response)
{
var expectedResult = param1 + param2 + param5;
if( expectedResult !== response.result) {
alert( "error");
}
});Java code:



@DirectMethod
public String test_serverProblematicLongString2( String param1, String param2,
int param3, int param4, String param5 )
{
String expectedParam1 = "symphony";
String expectedParam2 = " select * from `scrapbucketout` where parent='beb8596a-1dc0-4e61-9297-3267ab5d1528' and type='file'";
int expectedParam3 = 5;
int expectedParam4 = 5;
String expectedParam5 =
"rO0ABXNyACdjb20uYW1hem9uLnNkcy5RdWVyeVByb2Nlc3Nvci5Nb3JlVG9rZW7racXLnINNqwMA C0kAFGluaXRpYWxDb25qdW5jdEluZGV4WgAOaXNQYWdlQm91bmRhcnlKAAxsYXN0RW50aXR5SURa AApscnFFbmFibGVkSQAPcXVlcnlDb21wbGV4aXR5SgATcXVlcnlTdHJpbmdDaGVja3N1bUkACnVu aW9uSW5kZXhaAA11c2VRdWVyeUluZGV4TAANY29uc2lzdGVudExTTnQAEkxqYXZhL2xhbmcvU3Ry aW5nO0wAEmxhc3RBdHRyaWJ1dGVWYWx1ZXEAfgABTAAJc29ydE9yZGVydAAvTGNvbS9hbWF6b24v c2RzL1F1ZXJ5UHJvY2Vzc29yL1F1ZXJ5JFNvcnRPcmRlcjt4cAAAAAQATw0PyGR0wAAAAAAAAQAA AACnEObjAAAAAAFwdAAkYmViODU5NmEtMWRjMC00ZTYxLTkyOTctMzI2N2FiNWQxNTI4fnIALWNv bS5hbWF6b24uc2RzLlF1ZXJ5UHJvY2Vzc29yLlF1ZXJ5JFNvcnRPcmRlcgAAAAAAAAAAEgAAeHIA DmphdmEubGFuZy5FbnVtAAAAAAAAAAASAAB4cHQACUFTQ0VORElOR3g=";
assert param1.equals(expectedParam1);
assert param2.equals(expectedParam2);
assert param3 == expectedParam3;
assert param4 == expectedParam4;
assert param5.equals(expectedParam5);
return param1 + param2 + param5;
}

Regards,

Sesshomurai
6 Feb 2010, 4:50 AM
It works. Had to do a clean build, redeploy to flush some compiled classes out.

pagullo
6 Feb 2010, 6:16 AM
It works. Had to do a clean build, redeploy to flush some compiled classes out.

Great news! I thought I was starting to turn crazy when I tried this and it worked for me -as always did

I have to confess I don't like the whole approach very much, and so I would like to try the following alternative code.


private Object[] getMethodParameters(Class<?>[] parameterTypes,
JsonElement[] jsonParameters)
{
assert parameterTypes != null;
assert jsonParameters != null;

Object[] result = new Object[jsonParameters.length];
for( int i = 0; i < jsonParameters.length; i++ ) {
JsonElement jsonValue = jsonParameters[i];
Class<?> parameterType = parameterTypes[i];
Object value = null;
if( isString(jsonValue)) {
if( parameterType.equals(String.class)) {
value = jsonValue.getAsString();
}
else if(parameterType == char.class || parameterType == Character.class) {
value = new Character(jsonValue.getAsString().charAt(0));
}
else {
String json = jsonValue.toString();
value = getGson().fromJson(json, parameterType);
}
}
else {
String json = jsonValue.toString();
value = getGson().fromJson(json, parameterType);
}
result[i] = value;
}
return result;
}Would you be so kind as to try this in your environment? Just implement getMethodParameters in JsonRequestProcessor as above and check whether it works for you. It removes the ugly reEncode thing, which I really dislike.

This issue has been so elusive I have never been able to reproduce it. I don't want to change the way I handle this unless those who have had the issue can confirm me this works for them too!

Best regards,

Sesshomurai
6 Feb 2010, 12:27 PM
Sure thing. I'll give it a try.

zaqwsxqwer
10 Feb 2010, 1:04 AM
Please, check DJN 1.2 beta 3 and let me know if it works for you.



ok, it works. Thanks.

hschaefer123
10 Feb 2010, 1:01 PM
Hi Developer,
i'm doing my first tests with Tests with DJN and need a
deserialization from the DirectFormPost "formParameters"
into my own Java Class.

I am using Hibernate/JPA generated Classes and would like
to have something similar to
MyTableClass abc = ... deserialize(formParameters, MyTableClass.class)

I notices that GSON can do something with JSON, but the needed param
formParameter has to be a Map.

What is the way to transfer the posted Data into my Class.
The Map.Keys are identically with the Class Attributes,
because i directly returned the MyTableClass for loading the form.

Maybe i can use (JsonArray formParameter...) as constructor and use the
GSON.deserialize?!?

I used the following Method to catch the data
@DirectFormPostMethod public SubmitResult updateBasicInfo( Map<String, String> formParameters,
{
}
Map<String, FileItem> fileFields )
...
MyTableClass entity = new MyTableClass();
// i need to copy the data for mapping attributes type safe
entity = copyCorresponding(formParameter)
...
---------------

Another problem is using store with paging, sorting and filtering. using
>public StoreResult find(int start, int limit, String sort, String dir, JsonObject filters)
for a posted JSON like
{"action":"Adresse","method":"find","data":[0,10,"adressenId","ASC",{"adressenId":"abc","internKundenId":"def"}],"type":"rpc","tid":4}
works well for all params except filters.
How can i access/deserialize the filters object to java?

Maybe someone can help me.

Best wishes,
Holger

minneyar
12 Feb 2010, 7:44 AM
I can confirm that your alternative code works fine for me.

pagullo
15 Feb 2010, 12:21 AM
I have released DirectJNgine 1.2 RC1 today.

As always, you can find it here: http://code.google.com/p/directjngine/

This new release runs on top of ExtJs 3.1.1, which is the officially supported ExtJs version.

I release this in the hope that those running it in non-Windows systems can check that it works as expected in their environment.

stdunbar
16 Feb 2010, 10:55 AM
I'm looking to build a chat-like system and was going to use ExtJS and, potentially, DirectJNgine. I haven't seen particularly good or clear information regarding server push type of technologies with ExtJS 3.1.x even though it is checked off as "done" in the ExtJS road map.

I understand that in the Java server world asynchronous server updates are not at all standardized. There are Comet implementations included in Tomcat an Jetty but each of them is proprietary. The 3.0 Servlet spec addresses this and Glassfish 3.0 support this. So the landscape is harsh at best.

So, if I understand the DirectJNgine docs it looks like I'm limited to client initiated polling at this time. Is this correct? Am I going down the wrong path to use ExtJS on the front and Java on the back? Nothing has been implemented yet so I'm still very open.

Thanks for any info.

pagullo
17 Feb 2010, 12:53 PM
So, if I understand the DirectJNgine docs it looks like I'm limited to client initiated polling at this time. Is this correct? Am I going down the wrong path to use ExtJS on the front and Java on the back?

The ExtDirect specification provides support for client-initiated polling only, and so does DirectJNgine.

I don't think your app will scale very well if you use client initiated polling. But if the number of clients is not big and the updates need not be very fast, you might find this workable.

pagullo
23 Feb 2010, 7:33 AM
Today I have released DirectJNgine 1.2.

For more details, you can find the announcement here (http://softdevbuilttolast.wordpress.com/2010/02/23/directjngine-1-2-final-is-out/).

To all, thank you for your feedback and criticism.

Best regards,

Whatty
23 Feb 2010, 3:53 PM
Today I have released DirectJNgine 1.2.

For more details, you can find the announcement here (http://softdevbuilttolast.wordpress.com/2010/02/23/directjngine-1-2-final-is-out/).

To all, thank you for your feedback and criticism.

Best regards,


Pagullo,

I am not 100% sure if you have been following the posts regarding the DirectJNgine / Spring integration but I would like to open a conversion regarding on how to support this type of external DI / IOC container (even more important once these features are rolled into JDK 7) in the contet of the DirectJNgine.

As expected, I have adapted / extended and unfortunately changed some of the base classes in the DirectJNgine to support the Spring integration (which I did not start but picked up from someone else), and now that the DirectJNgine has changed underneath me, there is a integration exercise that I must undertake again to bring the base version of what the Spring / DirectJNgine integration is based upon up to your latest version.

I would love to see some sort of open integration API / configuration option to allow these types of external DI containers (such as SPRING) to hook into the base DirectJNgine framework but that is going to take some collaboration between the authors of DirectJNgine and either myself or others in the community that require this type of integration.

Further to this the Spring community / authors may be willing to contribute to this integration, since there are number of features in the Spring framework that possibily could be leverage in the context of the DirectJNgine (such annotation based Spring configuration and bean lifecycle management). Logically it seems to make sense but I have yet to approach anyone in the Spring community (aka authors) about this type of integration.

Would it be possible to have a conversation regarding this and how to proceed.

Thanks in advance.

Whatty

MoShAn480
23 Feb 2010, 7:49 PM
Hi,

I am working on a Spring MVC integration. Project can be found at:

http://code.google.com/p/springextjs/wiki/UsingLatestSpringextjs

pagullo
26 Feb 2010, 3:40 AM
Pagullo,

I am not 100% sure if you have been following the posts regarding the DirectJNgine / Spring integration


I followed the "Spring saga" with interest.
In fact, I helped Vincent Lagorce quite a bit when he attempted to provide Spring integration. I think you might have used his work as a starting point -not sure, though.


As expected, I have adapted / extended and unfortunately changed some of the base classes in the DirectJNgine to support the Spring integration (which I did not start but picked up from someone else), and now that the DirectJNgine has changed underneath me, there is a integration exercise that I must undertake again to bring the base version of what the Spring / DirectJNgine integration is based upon up to your latest version.

I would love to see some sort of open integration API / configuration option to allow these types of external DI containers (such as SPRING) to hook into the base DirectJNgine framework but that is going to take some collaboration between the authors of DirectJNgine and either myself or others in the community that require this type of integration.
Unfortunately, I don't have much time left nowadays, so I can't commit to consider or perform long-term modifications to DJN to support Spring right now.

When I announced 1.2 beta, a main concern was to open this kind of negotiation with people wanting to extend DJN, precisely to avoid this "DJN moving under my feet" thing. We've been *very* unlucky with the timing, because I would have loved to see someone seize the opportunity and provide robust Spring integration!

That said, I think you'll need very little effort to move to DJN 1.2.

You might want to take a look at the code for the classes in the "ssm" package, which implement the lifecycle support for the new session and application scoped objects. You will probably need to do something very similar for Spring.

Feel free to post here whenever you have some problem moving to the newest DJN version, and I will do my best to solve the issues you might encounter.

Regards,

Whatty
26 Feb 2010, 6:58 AM
Understand we are all very busy, and yes "the moving under my feet thing" is exactly what I am hoping to avoid.

I believe that I have taken what was started by Vincent Lagorce and extended it further hooking into SSM layer mentioned by you and also provided some support for "external names" in the Action layer (decoupling of the action class from the external name known in the API), which was required by Spring.

I will execute a diff against the code base that I started with and the newest code base and hopefully the integration (re-integration) exercise will not be too painful.

Once I get it working on the newest version I will post back my Spring integrated version for all to use if required (but of course caveat emptor applies).

In particular the areas that caused me the most problem was the usage of private methods, which limited my ability to override behavior at certain key points without completely re-implementing the methods / classes and most of the changes that I made in the base classes (your code) was related to make methods protected (as opposed to private) and then overriding appropriately in my classes.

I expect that the library will reach a stable state as some point in time (if not already) and no major upgrades are on the horizon at the moment, so hopefully this re-integration exercise will not be occuring all that frequently.

Thanks for the effort on the library and your assistance.

Whatty

tungchau
2 Mar 2010, 4:01 PM
I am using DirectJNGine. Does anybody have an answer for the following post?
http://www.extjs.com/forum/showthread.php?p=442554#post442554

tungchau
2 Mar 2010, 5:11 PM
Hi,
I found out that DirectJNGine does not support Action class that implemeted a Java Interface. It threw "IllegalArgumentException: object is not an instance of declaring class" when I tried to invoke the Action. For example, if I have MyAction class that implement IAction as the following:


@Service("MyAction")
public class MyAction implements IAction {

//...
@DirectMethod
public String doEcho(String n) {
return n;
}

Calling the remote API as the following:

MyAction.doEcho("Tung Chau", function(p, response){

Ext.Msg.alert("Message::"+response.status,(response.status)? response.result : response.message);
});


If I make MyAction class NOT to implement IAction interface, then everything will work.
Is this a Spring bean configuration problem, not DirectJNGine problem?

tungchau
2 Mar 2010, 7:04 PM
Hi Pedro,
I had a problem described at the following thread:
http://www.extjs.com/forum/showthread.php?p=442554#post442554

I wonder if the problem related to GSON configuration, not DirectJNGine?

Thanks,
Tung Chau

pagullo
3 Mar 2010, 12:43 AM
Hi,
I found out that DirectJNGine does not support Action class that implemeted a Java Interface. It threw "IllegalArgumentException: object is not an instance of declaring class" when I tried to invoke the Action. For example, if I have MyAction class that implement IAction as the following:


@Service("MyAction")
public class MyAction implements IAction {

//...
@DirectMethod
public String doEcho(String n) {
return n;
}
Calling the remote API as the following:

MyAction.doEcho("Tung Chau", function(p, response){

Ext.Msg.alert("Message::"+response.status,(response.status)? response.result : response.message);
});
If I make MyAction class NOT to implement IAction interface, then everything will work.



DirectJNgine *does* support actions implementing interfaces: I have such an action working correctly in front of me. Please, check your facts before making such assertions, as other potential users might be lead to think DJN belongs to the "non-working/just crap" software category, which I think is not the case.

Now, let's see whether I can help you.



Is this a Spring bean configuration problem, not DirectJNGine problem?
Since I am no Spring programmer, I can only guess about what's going on. But, to me, it looks like this is some configuration problem, or you need to create some kind of DJN/Spring bridge. Maybe Spring is playing proxy-like games, creating and instantiating a different class where MyAction is expected? Can you check that?

Besides, I think Vincent Lagorce and Whatty have some software that helps bridge the DJN/Spring gap, did you check it?

As an aside, there are a pair of good ideas/best practices in DJN can be helpful in your scenario:

a) Use "clean" action classes whose *only* purpose is to interact with the Javascript side of the world, probably just redirecting the call to the real object in charge.
This takes care of problems due to external lifecycle cotnrol, proxies being generated under-the-hood, etc.

b) Define "clean" data exchange classes.
This takes care of the potential problems you can find with very complex Java structures, that can stretch GSON a bit too much. You can alwasys configure GSON adequately, but this can be more complicated than creating simpler data exchange classes.

I have found these practices invaluable when "strange" things happen. Integration between frameworks/libraries can be a nightmare, and making things as simple as possible can go a long way to make it easier.

Regards,

pagullo
3 Mar 2010, 1:08 AM
Hi Pedro,
I had a problem described at the following thread:
http://www.extjs.com/forum/showthread.php?p=442554#post442554

I wonder if the problem related to GSON configuration, not DirectJNGine?

Thanks,
Tung Chau

GSON is the one in charge of JSON handling. I think it is having a hard time handling interfaces.

You should probably pass concrete classes.

hschaefer123
8 Mar 2010, 5:33 AM
Hi,
i have just tested the feature concerning stateful actions.

The action behaves the way expected, but for me i am missing
a feature like the servlet init() and destroy() methods.

The init() can be realized via a singleton class member, instantiated inside method,
but how should the destroy been handled?

I would like to exclude 'expensive/inperformant' functionality inside session scope,
but i have to close/destroy depending things on session close.

Any ideas?

Best wishes,
Holger

pagullo
9 Mar 2010, 2:23 AM
Hi,
i have just tested the feature concerning stateful actions.

The action behaves the way expected, but for me i am missing
a feature like the servlet init() and destroy() methods.

The init() can be realized via a singleton class member, instantiated inside method,
but how should the destroy been handled?

I would like to exclude 'expensive/inperformant' functionality inside session scope,
but i have to close/destroy depending things on session close.

Any ideas?

Best wishes,
Holger

I think your strategy should be exactly the same you would use with "expensive" objects stored in the session: just ignore the fact that they are instantiated by DirectJNgine.
Maybe you can use HttpSessionListener to perform expensive resource cleanup.

You will probably need to find some of the objects stored in the session by DJN to perform cleanup. Session scoped objects are stored in the HttpSession with the "DirectJNgine.SESSION.xxx" name, where "xxx" is the action name -as set in the @DirectAction annotation (or the class name, without the package).

Objects with application scope are stored as "DirectJNgine.APPLICATION.xxx" in the ServletContext.

Regards

Sesshomurai
13 Mar 2010, 6:09 AM
Hi,
I was reading the 1.2 manual and it mentions briefly about the nature of the callback function from a simple method call (not a store or form) and it would discuss more of it later in the guide. I didn't notice any further info about it.

So my question is, how are the callback functions used to determine success or failure of the method call ,etc.

Thanks!! Great product here.

pagullo
14 Mar 2010, 11:22 PM
Hi,
I was reading the 1.2 manual and it mentions briefly about the nature of the callback function from a simple method call (not a store or form) and it would discuss more of it later in the guide. I didn't notice any further info about it.

So my question is, how are the callback functions used to determine success or failure of the method call ,etc.


Not sure what part of the documentation you are talking about, but maybe this will help (from page 13):


The call to multiply is a bit more interesting, because it shows how to handle server errors:



TestAction.multiply(num.getValue(), function(result, e) {
var t = e.getTransaction();
if(e.status) {
out.append(String.format(
'<p><b>Successful call to {0}.{1} with ' +
'response:</b><xmp>{2}</xmp></p>',
t.action, t.method, Ext.encode(result)));
}
else {
out.append(String.format(
'<p><b>Call to {0}.{1} failed with message:</b><xmp>{2}</xmp></p>',
t.action, t.method, e.message));
}
out.el.scrollTo('t', 100000, true);
});

Here, we get the event transaction and check its status: if it is true, the execution of the application method finished successfully, and you can safely use the result. Else, the execution finished with a server error. For all intents and purposes this is considered to be a server error by DirectJNgine, and is notified as such to Ext Direct.

When there is a server error, the event received by the function handling the result will have a message field, providing some kind of explanation about the problem, and if in debug mode, a where field providing additional information. This field will always be an empty string when not in debug mode.

DirectJNgine provides as message the name of the Java exception and the message it contains, while where contains the full stack trace of the exception.For more info, check the ExtJs documentation, as that's what defines how ExtDirect implementations should work. Besides, depending on the context, you might find that there are specific ways to handle errors.

Hope this helps


Thanks!! Great product here.Thanks :-)

Sesshomurai
15 Mar 2010, 6:28 PM
Ahhh great. Thanks for pointing that out Pedro. Much appreciated.

vlagorce
22 Mar 2010, 4:53 AM
I am pleased to announce that I'll finish the spring integration I have start many month ago..