I have a weird problem with deferred binding. I have defined the following module:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Defines the usercategory property and its provider function. -->
<module>
<define-property name="usercategory" values="c00,c01,c02" />
<collapse-property name="usercategory" values="*" />
<property-provider name="usercategory"><![CDATA[
// Look for the usercategory cookie
var cs = document.cookie.split(';');
for (var i = 0; i < cs.length; i++) {
var name = cs[i].substr(0, cs[i].indexOf("="));
var value = cs[i].substr(cs[i].indexOf("=") + 1);
name = name.replace(/^\s+|\s+$/g,"");
if (name == "usercategory") {
return unescape(value);
}
}
return "c00";
]]></property-provider>
</module>
which sets the property usercategory by looking at the value of a cookie named usercategory.
I use this property application.gwt.xml to defer binding of some classes, for example:
<inherits name="com.example.UserCategory"/>
<replace-with class="com.example.client.ui.menu.MainMenuView01">
<when-type-is class="com.example.client.ui.menu.MainMenuView"/>
<when-property-is name="usercategory" value="c01"/>
</replace-with>
This works like a charm when I'm in development mode (i.e. when running my app from within Eclipse). However, if I compile the app and deploy it (in Jetty, but I don't this this is the problem), then deferred binding does not seem to work, and the expected classes are not loaded. I've checked and the cookie is set up properly with the correct value c01, but class com.example.client.ui.menu.MainMenuView01 is not loaded.
Am I missing something? Am I doing something wrong?
Thank you in advance!
There are two possibilities. You are doing something wrong, or there is another bug in GWT compiler. I've tried to implement a case like your and it was working when compiled without any problems. So most likely there can be some error on your side. So what i recommend to do is to compile app with -style PRETTY and see how it was compiled. find function named com_example_client_ui_menu_MainMenuView(), and see if it able to create MainMenuView01, try to debug it and etc. Anyway this kind of stuff should be working without any problems.
Also try to debug your property provider (and use vars $doc and $wnd in property provider instead of window)
Another possible case is that the cookie might be not readable from JS
I figured out what the problem was, and I'm writing it here in case others might be interested.
The module that I defined (see code in my question) defines a property whose value is taken from a cookie, that is generated after the user logs in the application.
Originally I had a GWT Place for the login, and when the user successfully authenticated the application moved to another Place. In this case when the user enter the application, and the GWT Javascript is downloaded to the browser, the cookie is not set yet (because the user has not performed login yet). Therefore the deferred binding does not work, and the expected classes (like com.example.client.ui.menu.MainMenuView01) are not loaded.
I have no idea why this works correctly when run in development mode. Anyway. the solution that I implemented is to move the login phase outside of the GWT application, and when the login is successful, I add the cookie and the redirect the user to the actual GWT application.
Related
I have added a custom locator in protractor, below is the code
const customLocaterFunc = function (locater: string, parentElement?: Element, rootSelector?: any) {
var using = parentElement || (rootSelector && document.querySelector(rootSelector)) || document;
return using.querySelector("[custom-locater='" + locater + "']");
}
by.addLocator('customLocater', customLocaterFunc);
And then, I have configured it inside protractor.conf.js file, in onPrepare method like this:
...
onPrepare() {
require('./path-to-above-file/');
...
}
...
When I run my tests on the localhost, using browser.get('http://localhost:4200/login'), the custom locator function works absolutely fine. But when I use browser.get('http://11.15.10.111/login'), the same code fails to locate the element.
Please note, that the test runs, the browser gets open, user input gets provided, the user gets logged-in successfully as well, but the element which is referred via this custom locator is not found.
FYI, 11.15.10.111 is the remote machine (a virtual machine) where the application is deployed. So, in short the custom locator works as expected on localhost, but fails on production.
Not an answer, but something you'll want to consider.
I remember adding this custom locator, and encounter some problems with it and realised it's just an attribute name... nothing fancy, so I thought it's actually much faster to write
let elem = $('[custom-locator="locator"]')
which is equivalent to
let elem = element(by.css('[custom-locator="locator"]'))
than
let elem = element(by.customLocator('locator'))
And I gave up on this idea. So maybe you'll want to go this way too
I was able to find a solution to this problem, I used data- prefix for the custom attribute in the HTML. Using which I can find that custom attribute on the production build as well.
This is an HTML5 principle to prepend data- for any custom attribute.
Apart from this, another mistake that I was doing, is with the selector's name. In my code, the selector name is in camelCase (loginBtn), but in the production build, it was replaced with loginbtn (all small case), that's why my custom locater was not able to find it on the production build.
I have been trying to overwrite the target.url with a variable using the Assign Message Policy. Per other solutions, I have put this in the "Target EndPoint" Section. The issue is, unless I hard-code the root section of the URL, the substitution fails. I have tried all the commented VALUE stmts below with and then started adding the "REF"stmts to attempt to solve the issue - to no avail. You can see I have tried cutting the target into various snippets using Extract policies, but cannot get a solution that works.
Thanks for help.
For the purposes of the code snippet below
entireURL = "http://my.root.url/thestuff/morestuff"
AppServerURL = "my.root.url/thestuff/morestuff"
AppServerRoot = "my.root.url"
AppServerSfx = "thestuff/morestuff"
codee from Assign Message Policy
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Post-to-named-serverL">
<DisplayName>Post to named server</DisplayName>
<FaultRules/>
<Properties/>
<AssignVariable>
<Name>target.url</Name>
<Value>http://${AppServerRoot}/{AppServerSfx}</Value>
<Ref/>
<!--
<Value>http://my.root.url/{AppServerSfx}</Value> works but I need the root changed
<Value>http://{AppServerRoot}/{AppServerSfx}</Value>
<Value>http://${AppServerRoot}/{AppServerSfx}</Value>
<Value>http://{AppServerURL}</Value>
<Value>http://${AppServerURL}</Value>
<Value>entireURL</Value>
<Value>{entireURL}</Value> -- this was my first try
<Value>${entireURL}</Value>
<Ref>entireURL</Ref>
<Ref>{entireURL}</Ref>
<Ref>${entireURL}</Ref>
-->
</AssignVariable>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>
You are correctly putting the target.url manipulation in the Target Request flow.
Using AssignMessage/AssignVariable can be limiting. The Value element doesn't allow you to do any variable substitutions.
The following worked for me:
<Ref>entireURL</Ref>
Ref also doesn't allow variable substitutions -- it just takes the name of the variable. Since you have to build the value of that variable ahead of time, using the Ref example above doesn't buy you much.
I usually accomplish target URL rewriting using a JavaScript callout with code similar to the following:
var appServerRoot = context.getVariable("AppServerRoot");
var appServerSfx = context.getVariable("AppServerSfx");
context.setVariable("target.url", "http://" + appServerRoot + "/" + appServerSuffix);
In my project, there are additional (non-wicket) applications, which need to know the URL representation of some domain objects (e.g. in order to write a link like http://mydomain.com/user/someUserName/ into a notification email).
Now I'd like to create a spring bean in my wicket module, exposing the URLs I need without having a running wicket context, in order to make the other application depend on the wicket module, e.g. offering a method public String getUrlForUser(User u) returning "/user/someUserName/".
I've been stalking around the web and through the wicket source for a complete workday now, and did not find a way to retrieve the URL for a given PageClass and PageParameters without a current RequestCycle.
Any ideas how I could achieve this? Actually, all the information I need is somehow stored by my WebApplication, in which I define mount points and page classes.
Update: Because the code below caused problems under certain circumstances (in our case, being executed subsequently by a quarz scheduled job), I dived a bit deeper and finally found a more light-weight solution.
Pros:
No need to construct and run an instance of the WebApplication
No need to mock a ServletContext
Works completely independent of web application container
Contra (or not, depends on how you look at it):
Need to extract the actual mounting from your WebApplication class and encapsulate it in another class, which can then be used by standalone processes. You can no longer use WebApplication's convenient mountPage() method then, but you can easily build your own convenience implementation, just have a look at the wicket sources.
(Personally, I have never been happy with all the mount configuration making up 95% of my WebApplication class, so it felt good to finally extract it somewhere else.)
I cannot post the actual code, but having a look at this piece of code will give you an idea how you should mount your pages and how to get hold of the URL afterwards:
CompoundRequestMapper rm = new CompoundRequestMapper();
// mounting the pages
rm.add(new MountedMapper("mypage",MyPage.class));
// ... mount other pages ...
// create URL from page class and parameters
Class<? extends IRequestablePage> pageClass = MyPage.class;
PageParameters pp = new PageParameters();
pp.add("param1","value1");
IRequestHandler handler = new BookmarkablePageRequestHandler(new PageProvider(MyPage.class, pp));
Url url = rm.mapHandler(handler);
Original solution below:
After deep-diving into the intestines of the wicket sources, I was able to glue together this piece of code
IRequestMapper rm = MyWebApplication.get().getRootRequestMapper();
IRequestHandler handler = new BookmarkablePageRequestHandler(new PageProvider(pageClass, parameters));
Url url = rm.mapHandler(handler);
It works without a current RequestCycle, but still needs to have MyWebApplication running.
However, from Wicket's internal test classes, I have put the following together to construct a dummy instance of MyWebApplication:
MyWebApplication dummy = new MyWebApplication();
dummy.setName("test-app");
dummy.setServletContext(new MockServletContext(dummy, ""));
ThreadContext.setApplication(dummy);
dummy.initApplication();
I want to customize Surf Platform Root-Scoped API specifically user object. That means add new property or method to user object to check the user is in certain group in header.inc.ftl [in share] like `<#if user.isAdmin>
How can I implement this?
Is Alfresco Root Scoped Objects can be used as Surf Platform Root-Scoped object?
I have no idea of customizing surf platform root object. Can anyone help me???
Not quite sure what you are trying to accomplish, but the role security model is hardcoded in spring-surf/spring webscripts. There is guest, user and admin. If what you want is another analogous role you'll have to hack the spring-surf libaries, namely:
org/springframework/extensions/surf/mvc/PageView.java
org/springframework/extensions/webscripts/ScriptUser.java
org/springframework/extensions/webscripts/Description.java
org/springframework/extensions/webscripts/connector/User.java
This is what I had to do to implement user.isEmployee. This approach allows you to literally treat your new role just as the others.
you can use
<authentication>employee</authentication>
in page descriptors or
<item type="link" permission="employee" id="people">/people-finder</item>
on the navigation.
Just checking whether the user is in a certain group in a certain webscript is a whole diffrent story and does not provide the same functionality.
If what you want is the latter, you should make a call to
/alfresco/service/api/groups/{shortName}
miss
and works through the response.
Update: The item permission attribute requires a little more tweaking.
In header.get.js, propagate the new role to it gets processed properly in header.inc.ftl:
model.permissions =
{
guest: user.isGuest,
admin: user.isAdmin,
employee : user.isEmployee
};
you could try (in JavaScript I managed something like) this:
user = Application.getCurrentUser(context);
String userName = user.getUserName();
user.isAdmin() >>> result return true if user logining is admin
or in JSP:
#{NavigationBean.currentUser.admin == true}
Sorry, i noticed now you was talking about Surf Platform root objects, but the link you put there, is deprecated for Alfresco versions above 3.3. You still use something so old?
If you manage to use JavaScript API's you could use "person" root object, with boolean isAdmin().
Hi
I wrote code in one of the entry point class as:
if(RootPanel.get("fb-root") != null)
form = new BloodDonorForm(Constants.INSERT, null, Constants.FACEBOOK, Constants.BLOOD_DONOR_REGISTER_FORM);
else
form = new BloodDonorForm(Constants.INSERT, null, null, Constants.BLOOD_DONOR_REGISTER_FORM);
This used to work fine sometime back for sure (don't remember when I checked this last time). But now when I run the page in Firefox with firebug enabled I see the message like:
The "fb-root" div has not been created, auto-creating
So why is this done if it does not exist? I am sure I have tested this in past and this was not happening earlier.
This may be a change in GWT itself. That said, this isn't the best way to check for a dom element existing.
Instead, use Document.get().getElementById(String) to check for an element by id, and compare that with null. This will compile down to something very simple (probably just $doc.getElementById(id)), and won't create a widget yet (RootPanel is a widget) and the overhead that comes with that.