Apache Isis: How to implement your custom submit form or page properly? - wicket

I'm new at Apache Isis and I'm stuck.
I want to create my own submit form with editable parameters for search some entities and a grid with search results below.
Firstly, I created #DomainObject(nature=Nature.VIEW_MODEL) with search results collection, parameters for search and #Action for search.
After deeper research, I found out strict implementations for actions (For exapmle ActionParametersFormPanel). Can I use #Action and edit #DomainObject properties(my search parameters for action) without prompts?
Can I implement it by layout.xml?
Then I tried to change a component as described here: 6.2 Replacing page elements, but I was confused which ComponentType and IModel should I use, maybe ComponentType.PARAMETERS and ActionModel or implement my own IModel for my case.
Should I implement my own Wicket page for search and register it by PageClassList interface, as described here: 6.3 Custom pages
As I understood I need to replace page class for one of PageType, but which one should I change?
So, the question is how to implement such issues properly? Which way should I choose?
Thank you!
===================== UPDATE ===================
I've implemented HomePageViewModel in this way:
#DomainObject(
nature = Nature.VIEW_MODEL,
objectType = "homepage.HomePageViewModel"
)
#Setter #Getter
public class HomePageViewModel {
private String id;
private String type;
public TranslatableString title() {
return TranslatableString.tr("My custom search");
}
public List<SimpleObject> getObjects() {
return simpleObjectRepository.listAll();
}
#Action
public HomePageViewModel search(
#ParameterLayout(named = "Id")
String id,
#ParameterLayout(named = "Type")
String type
){
setId(id);
setType(type);
// finding objects by entered parameters is not implemented yet
return this;
}
#javax.inject.Inject
SimpleObjectRepository simpleObjectRepository;
}
And it works in this way:
I want to implement a built-in-ViewModel action with parameters without any dialog windows, smth like this:
1) Is it possible to create smth like ActionParametersFormPanel based on ComponentType.PARAMETERS and ActionModel and use this component as #Action in my ViewModel?
2) Or I should use, as you said, ComponentType.COLLECTION_CONTENTS? As I inderstand my search result grid and my search input panel will be like ONE my stub component?
Thank you.

We have a JIRA ticket in our JIRA to implement a filterable/searchable component, but it hasn't yet made it to the top of the list for implementation.
As an alternative, you could have a view model that provides the parameters you want to filter on as properties, with a table underneath. (I see you asked another question here on SO re properties on view models, so perhaps you are moving in that direction also... I've answered that question).
If you do want to have a stab at implementing that ticket, then the ComponentTYpe to use is COLLECTION_CONTENTS. If you take a look at the isisaddons, eg for excel or gmap3 then it might help get you started.
======= UPDATE TO ANSWER (based on update made to query) ==========
I have some good news for you. v1.15.0-SNAPSHOT, which should be released in the couple of weeks, has support for "inline prompts". You should find these give a user experience very similar to what you are after, with no further work needed on your part.
To try it out, check out the current trunk, and then load the simpleapp (in examples/application/simpleapp). You should see that editing properties and invoking actions uses the new inline prompt style.
HTH
Dan

Related

Ignore play framework form errors at different views

i'd like to know whether I could ignore play standard validation when I want to. For instance, let's imagine I have a Entity called Car just like
#Entity
public class Car{
#Id
private Long id;
#Required
private String model;
#Required
private String hiddenField; //important but doesn't appear in some cases (some usecases)
}
In order to make it clearer, then
Case 1
#(carForm : Form[Car])
#import helper._
#form(routes.controller.foo.bar) {
#inputText(carForm("model"))
<input type="submit">
}
Case 2
#(carForm : Form[Car])
#import helper._
#form(routes.controller.foo.bar) {
#inputText(carForm("model"))
#inputText(carForm("hiddenField"))
<input type="submit">
}
Then I have a Play.data.Form object, and it has errors cause i haven't filled model or the hiddenField that was given as exmple. But, actually, i have some situations that this hidden doesn't even appear (case 1), i mean, there's no input called that, as the user is not allowed to edit it that time. So, if I have two usecases, where at the first, all inputs are there and they are supposed to be filled, but the other one has no 'hiddenField' input, but, altought, it's still required by my model, and, of course, a form submitted without it has error as well, what should I do?. How was I supposed to deal with it? I have one model, but validation may be different in one case to another, and i wanna it to be server side, not jquery nor pure javascript.
I tried to discardErrors through
(Imagine it was submitted from case 1)
MyForm<Car> myCarForm = Form.form(Car.class).bindFromRequest();
//it has errors, sure it does, hiddenField was required and that field didn't even exist at screen.
myCarForm.discardErrors(); //ok, error hashmap is empty right now
myCarForm.get(); // anyway, no value here.
//myCarForm.data(); //for sure i could retrieve field by field and remount object that way, but that looks hacky and hardworking
Then, any solution? Thank u all
I got it reading Play for Java book.
6.4.2 Partial Validation
A common use case is having multiple validation constraints for the same object
model. Because we’re defining our constraint on the object model, it’s normal to have
multiple forms that refer to the same object model. But these forms might have different
validation constraints. To illustrate this use case, we can imagine a simple wizard in
which the user inputs a new product in two steps:
1 The user enters the product name and submits the form.
2 The user enters the product EAN number and the description.
We could validate the product’s name during step 2, but displaying an error message
for the product name at that point would be weird. Fortunately, Play allows you to perform
partial validation. For each annotated value, we need to indicate at which step it
applies. We can do that with the help of the groups attribute from our annotations.
Let’s change our Product model class to do that:
public Product extends Model {
public interface Step1{}
public interface Step2{}
#Required(groups = Step1.class)
public String name;
#Required(groups = Step2.class)
public String ean;
}
Then, at Controller
// We re//strict the validation to the Step1 "group"
Form<Product> productForm =
form(Product.class, Product.Step1.class).bindFromRequest();
Thanks!
Yes you can achieve the solution to this problem. what's happening in this case is every time you map your request to model car it will always look for JPA validations for every property then it looks for validate() method present inside that model, if that method returns null then it doesn't pass any error and perform the normal execution, but if it returns any thing then it maps it to form errors.
You can return error mapping to specific field or you can just return a string that will be considered as a global error.
In your case solution is :
#Entity
public class Car{
#Id
private Long id;
private String model;
private String hiddenField; //important but doesn't appear in some cases (some usecases)
public List<ValidationError> validate() {
List<ValidationError> errors = new ArrayList<ValidationError>();
.
.
.
#Some logic to validate fields#
#if field invalid#
errors.add(new ValidationError("model", "errorMessage"));
.
.
.
return errors.isEmpty() ? null : errors;
}
Note: Just remove the JPA validation and use your logic in validate function to check according to the situation.
Ignores validations, like this:
myCarForm.discardErrors().get();
and does the validation otherwise, Jquery for example.

What are the options for REST frameworks in D? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 3 years ago.
Improve this question
I would like to use d to create a RESTful web application.
What are the most actively maintained and contributed projects that are worth considering? A short comparison of these web frameworks with pluses and minuses will be nice.
My search lead me to only one project, which seems like an excellent framework:
vibe.d
Are there other projects which are minimal in nature like sinatra?
I've heard good things about vibe.d http://vibed.org/
Though, I've never personally used it because I wrote my own libraries well before vibe came out.
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff
vibe is better documented, so you might be better off going there, but here's how my libraries work:
cgi.d is the base web interface (use -version=embedded_httpd when compiling to use its own web server instead of CGI if you want), and I offer some RESTy stuff in a separate file called web.d. It depends on cgi.d, dom.d, characterencodings.d, and sha.d. You might also want database.d and mysql.d for connecting to a mysql database.
The way web.d works is you just write functions and it automatically maps them to url and formats data.
http://arsdnet.net/cgi-bin/apidemo/add-some-numbers
The source code to that portion is:
import arsd.web;
class MySite : ApiProvider {
export int addSomeNumbers(int a, int b) { return a+b; }
}
mixin FancyMain!MySite;
web.d automatically generates the form you see there, parses the url into the types given, and formats the return value into either html, json, or sometimes other things (for example, objects can be made into tables).
There is also an envelopeFormat url param that can wrap it in more json, best for machine consumption:
http://arsdnet.net/cgi-bin/apidemo/add-some-numbers?a=1&b=2&format=json&envelopeFormat=json
web.d.php in my github shows one way you can consume it, and web.d itself automatically generates javascript functions to call from the client:
MySite.addSomeNumbers(10, 20).get(function(answer) { alert("Server replied: " + answer); });
answer would be of the type returned by the D function.
If you don't want/need the automatic function wrapping, cgi.d alone gives access to the basic info and writing functions:
void requestHandler(Cgi cgi) {
// there's cgi.get["name"], cgi.post["name"], or cgi.request("name"), kinda like php
cgi.write("hello ", cgi.request("name"));
}
mixin GenericMain!requestHandler;
But yeah, most the documentation that exists for my library is just me talking about it on forums... I think once you've done one function it isn't hard to figure out, but I'm biased!
edit: copy/paste from my comment below since it is pretty relevant to really getting RESTy:
I actually did play with the idea of having urls map to objects and the verbs go through: web.d also includes an ApiObject class which goes: /obj/name -> new Obj("name"); and then calls the appropriate methods on it. So GET /obj/name calls (new Obj("name")).GET();, same for POST, PUT, etc. Then /obj/name/foo calls (new Obj("name").foo(); with the same rules as I described for functions above.
But I don't use it as much as the plain functions for one because it is still somewhat buggy.... and it is still somewhat buggy because I don't use it enough to sit down and fit it all! lol
You use it by writing an ApiObject class and then aliasing it into the ApiProvider:
import arsd.web;
class MySite : ApiProvider {
export int addSomeNumbers(int a, int b) { return a+b; }
alias MyObject obj; // new, brings in MyObject as /obj/xxx/
}
And, of course, define the object:
class MyObject : ApiObject {
CoolApi parent;
string identifier;
this(CoolApi parent, string identifier) {
this.parent = parent;
this.identifier = identifier;
/* you might also want to load any existing object from a database or something here, using the identifier string, and initialize other members */
// for now to show the example, we'll just initialize data with dummy info
data.id = 8;
data.name = "MyObject/" ~ identifier;
}
/* define some members as a child struct so we can return them later */
struct Data {
int id;
string name;
Element makeHtmlElement() {
// for automatic formatting as html
auto div = Element.make("div");
import std.conv;
div.addChild("span", to!string(id)).addClass("id");
div.appendText(" ");
div.addChild("span", name).addClass("name");
return div;
}
}
Data data;
export Data GET() {
return data;
}
export Data POST(string name) {
parent.ensureGoodPost(); // CSRF token check
data.name = name;
// normally, you'd commit the changes to the database and redirect back to GET or something like that, but since we don't have a db we'll just return the modified object
return data;
}
// property accessors for the data, if you want
export int id() {
return data.id;
}
}
mixin FancyMain!MySite;
Then you can access it:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/
BTW the trailing slash is mandatory: this is one of the outstanding bugs I haven't gotten around to fixing yet. (The trailing slash code is more complicated than it should be, making this harder to fix that it might look.)
Anyway, you can see the object rendered itself as html via makeHtmlElement. This is a good time to showcase other formats:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=table
table, also try csv, and of course, json
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=json
or for machine consumption:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=json&envelopeFormat=json
and the property is available too:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/id
Another major outstanding bug is that the automatically generated Javascript functions can't access child objects at all. They only work on functions on the top level ApiProvider. Another bug that is harder to fix than it might seem, and I'm not particularly driven to do so because the top-level functions can do it all anyway. Of course, you could make the URLs yourself on the xmlhttprequest and access it that way.
Let's also demo POST by slapping together a quick form:
http://arsdnet.net/cgi-bin/apidemo2/poster
you can submit something and see the POST handler indeed reset the name. (BTW note the action has that trailing slash: without it, it silently redirects you! I really should fix that.)
Anyway, bugs notwithstanding, the core of it works and might be the closest thing to full blown REST D has right now.
At the moment of writing this text there is no framework for building true RESTful web services that I know of. However, you should be able to easily build one on top of vibe.d or Adam's web modules that he already mentioned above.
You can take a look at what I'm building. Still extremely alpha, but I'm attempting to build a Rails-like framework in D: http://jaredonline.github.io/action-pack/
I know this is a really late answer, but I figured someone might come by this one day, since it has been so long and a lot of changes has happened within the D community, especially towards web development.
With Diamond you can write RESTful web applications without hacking something together, since it supports it within the framework.
http://diamondmvc.org/docs/backend/#rest
You can try Hunt Framework.
routes setting
GET /user/{id} user.detail
app/UserController.d souce code:
module app.controller.UserController;
import hunt.framework;
class User
{
int id;
string name;
}
class UserController : Controller
{
mixin MakeController;
#Action
JsonResponse detail(int id)
{
auto user = new User;
user.id = id;
user.name = "test";
return new JsonResponse(user);
}
}
Request http://localhost:8080/user/123
{
"id": 123,
"name": "test"
}

Enforce Hyphens in .NET MVC 4.0 URL Structure

I'm looking specifically for a way to automatically hyphenate CamelCase actions and views. That is, I'm hoping I don't have to actually rename my views or add decorators to every ActionResult in the site.
So far, I've been using routes.MapRouteLowercase, as shown here. That works pretty well for the lowercase aspect of URL structure, but not hyphens. So I recently started playing with Canonicalize (install via NuGet), but it also doesn't have anything for hyphens yet.
I was trying...
routes.Canonicalize().NoWww().Pattern("([a-z0-9])([A-Z])", "$1-$2").Lowercase().NoTrailingSlash();
My regular expression definitely works the way I want it to as far as restructuring the URL properly, but those URLs aren't identified, of course. The file is still ChangePassword.cshtml, for example, so /account/change-password isn't going to point to that.
BTW, I'm still a bit rusty with .NET MVC. I haven't used it for a couple years and not since v2.0.
This might be a tad bit messy, but if you created a custom HttpHandler and RouteHandler then that should prevent you from having to rename all of your views and actions. Your handler could strip the hyphen from the requested action, which would change "change-password" to changepassword, rendering the ChangePassword action.
The code is shortened for brevity, but the important bits are there.
public void ProcessRequest(HttpContext context)
{
string controllerId = this.requestContext.RouteData.GetRequiredString("controller");
string view = this.requestContext.RouteData.GetRequiredString("action");
view = view.Replace("-", "");
this.requestContext.RouteData.Values["action"] = view;
IController controller = null;
IControllerFactory factory = null;
try
{
factory = ControllerBuilder.Current.GetControllerFactory();
controller = factory.CreateController(this.requestContext, controllerId);
if (controller != null)
{
controller.Execute(this.requestContext);
}
}
finally
{
factory.ReleaseController(controller);
}
}
I don't know if I implemented it the best way or not, that's just more or less taken from the first sample I came across. I tested the code myself so this does render the correct action/view and should do the trick.
I've developed an open source NuGet library for this problem which implicitly converts EveryMvc/Url to every-mvc/url.
Uppercase urls are problematic because cookie paths are case-sensitive, most of the internet is actually case-sensitive while Microsoft technologies treats urls as case-insensitive. (More on my blog post)
NuGet Package: https://www.nuget.org/packages/LowercaseDashedRoute/
To install it, simply open the NuGet window in the Visual Studio by right clicking the Project and selecting NuGet Package Manager, and on the "Online" tab type "Lowercase Dashed Route", and it should pop up.
Alternatively, you can run this code in the Package Manager Console:
Install-Package LowercaseDashedRoute
After that you should open App_Start/RouteConfig.cs and comment out existing route.MapRoute(...) call and add this instead:
routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
new DashedRouteHandler()
)
);
That's it. All the urls are lowercase, dashed, and converted implicitly without you doing anything more.
Open Source Project Url: https://github.com/AtaS/lowercase-dashed-route
Have you tried working with the URL Rewrite package? I think it pretty much what you are looking for.
http://www.iis.net/download/urlrewrite
Hanselman has a great example herE:
http://www.hanselman.com/blog/ASPNETMVCAndTheNewIIS7RewriteModule.aspx
Also, why don't you download something like ReSharper or CodeRush, and use it to refactor the Action and Route names? It's REALLY easy, and very safe.
It would time well spent, and much less time overall to fix your routing/action naming conventions with an hour of refactoring than all the hours you've already spent trying to alter the routing conventions to your needs.
Just a thought.
I tried the solution in the accepted answer above: Using the Canonicalize Pattern url strategy, and then also adding a custom IRouteHandler which then returns a custom IHttpHandler. It mostly worked. Here's one caveat I found:
With the typical {controller}/{action}/{id} default route, a controller named CatalogController, and an action method inside it as follows:
ActionResult QuickSelect(string id){ /*do some things, access the 'id' parameter*/ }
I noticed that requests to "/catalog/quick-select/1234" worked perfectly, but requests to /catalog/quick-select?id=1234 were 500'ing because once the action method was called as a result of controller.Execute(), the id parameter was null inside of the action method.
I do not know exactly why this is, but the behavior was as if MVC was not looking at the query string for values during model binding. So something about the ProcessRequest implementation in the accepted answer was screwing up the normal model binding process, or at least the query string value provider.
This is a deal breaker, so I took a look at default MVC IHttpHandler (yay open source!): http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/MvcHandler.cs
I will not pretend that I grok'ed it in its entirety, but clearly, it's doing ALOT more in its implementation of ProcessRequest than what is going on in the accepted answer.
So, if all we really need to do is strip dashes from our incoming route data so that MVC can find our controllers/actions, why do we need to implement a whole stinking IHttpHandler? We don't! Simply rip out the dashes in the GetHttpHandler method of DashedRouteHandler and pass the requestContext along to the out of the box MvcHandler so it can do its 252 lines of magic, and your route handler doesn't have to return a second rate IHttpHandler.
tl:dr; - Here's what I did:
public class DashedRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["action"] = requestContext.RouteData.GetRequiredString("action").Replace("-", "");
requestContext.RouteData.Values["controller"] = requestContext.RouteData.GetRequiredString("controller").Replace("-", "");
return new MvcHandler(requestContext);
}
}

GWT Editor Framework: Drop Down List

I'm looking for someone to point me in the right direction (link) or provide a code example for implementing a drop down list for a many-to-one relationship using RequestFactory and the Editor framework in GWT. One of the models for my project has a many to one relationship:
#Entity
public class Book {
#ManyToOne
private Author author;
}
When I build the view to add/edit a book, I want to show a drop down list that can be used to choose which author wrote the book. How can this be done with the Editor framework?
For the drop-down list, you need a ValueListBox<AuthorProxy>, and it happens to be an editor of AuthorProxy, so all is well. But you then need to populate the list (setAcceptableValues), so you'll likely have to make a request to your server to load the list of authors.
Beware the setAcceptableValues automatically adds the current value (returned by getValue, and defaults to null) to the list (and setValue automatically adds the value to the list of acceptable values too if needed), so make sure you pass null as an acceptable value, or you call setValue with a value from the list before calling setAcceptableValues.
I know it's an old question but here's my two cents anyway.
I had some trouble with a similar scenario. The problem is that the acceptable values (AuthorProxy instances) were retrieved in a RequestContext different than the one the BookEditor used to edit a BookProxy.
The result is that the current AuthorProxy was always repeated in the ValueListBoxwhen I tried to edit a BookProxy object. After some research I found this post in the GWT Google group, where Thomas explained that
"EntityProxy#equals() actually compares their request-context and stableId()."
So, as I could not change my editing workflow, I chose to change the way the ValueListBox handled its values by setting a custom ProvidesKey that used a different object field in its comparison process.
My final solution is similar to this:
#UiFactory
#Ignore
ValueListBox<AuthorProxy> createValueListBox ()
{
return new ValueListBox<AuthorProxy>(new Renderer<AuthorProxy>()
{
...
}, new ProvidesKey<AuthorProxy>()
{
#Override
public Object getKey (AuthorProxy author)
{
return (author != null && author.getId() != null) ? author.getId() : Long.MIN_VALUE;
}
});
}
This solution seems ok to me. I hope it helps someone else.

authorization on wicket component using wicket auth-role

I am using wicket 1.4.9 and implemented spring + wicket auth-role and using #AuthorizeInstantiation based on roles on pages. I have multiple custom roles.
I have followed this link to implement the basics:
https://cwiki.apache.org/WICKET/spring-security-and-wicket-auth-roles.html
After that I have implemented my own UserDetailsService to have my own roles/users from database.
Now, How can I impose controls on roles with components eg, Links,Buttons ? like
link A can be accessed only by SUPER_USER, DR_MANAGER. (roles comes from database).
I have done like this and it seems to work, but is that the good way to do this? OrbitWebSession is of type AuthenticatedWebSession.
#Override
public boolean isVisible() {
if(OrbitWebSession.get().getRoles().hasRole("SUPER_USER")){
return true;
}
return false;
}
thanks.
Overriding isVisible all the time is a major pain. Take a look at MetaDataRoleAuthorizationStrategy instead. You call authorize(Component component, Action action, String roles) with Action RENDER, and the roles you want to allow. This way the component, whatever it is, is automatically hidden for other roles provided that the authorization strategy is registered in your webapplication. Basically it does the same thing as Holms answer, except you don't have to subclass anything.
You are in the right track, the only change I would do is:
#Override
public boolean isVisible() {
return super.isVisible() && OrbitWebSession.get().getRoles().hasRole("SUPER_USER");
}
That way you don't accidentally override its default visible behavior for example if the parent component is not visible.
Using the #AuthorizeAction annotation you can control wether the component is rendered or not based on roles. It's quite easy to use, but you have to subclass the component that you want to authorize.
#AuthorizeAction(action = Action.RENDER, roles = { "SUPER_USER", "DR_MANAGER" })
class UserAdminPageLink extends BookmarkablePageLink<String> {
//Implementation…
}
add(new UserAdminPageLink("UserAdminPageLink", UserAdminPage.class));
Check out Wicket Examples - Authorization for some working code.