Your service can be per-thread no matter how it's built, to the best
of my knowledge with the only exception
being if you manually instantiate the service yourself... I should
clarify that one. If you use a builder method, you'll be instantiating
the service yourself, right?
But the service you return will be proxied by tapestry. If, however,
within a method, you create an object that /isn't/ going to be
returned, that object won't be proxied.
I'm probably muddying things up here a bunch. ;) Generally speaking, I
use the service binder approach:
public void bind(ServiceBinder binder) {
binder
.bind(RequestFilter.class,MyRequestFilter.class).withId("myfilter");
}
public void
contributeRequestHandler(OrderedConfiguration<RequestFilter> filter,
@InjectService("myfilter") RequestFilter filter) {
filter.add("myfilter",myfilter);
}
It might help you to understand the history.
In the beginning were builder methods. If you wanted to create a
service that could be referenced elsewhere, you had to use builder
methods, which took the form:
public static/*static is optional*/ ServiceInterface
buildServiceId(@InjectService("serviceid2") ServiceInterface2
someDependency,...) {
//instantiate your class and return it.
return new ServiceInterfaceImpl(someDependency);
}
//and contribute our service to something else:
public static void contributeSomeOtherService(Configuration conf,
@InjectService("serviceId") ServiceInterface someService) {
...
}
Later, it was realized that 95% of the time, the service id is the
interface name, so buildServiceId can be simplified in those cases to
just build. The older form is still necessary to support multiple
services of the same interface type with different service ids, such
as multiple RequestFilters.
public static ServiceInterface build(@InjectService("serviceid2")
ServiceInterface2 someDependency) {
return new ServiceInterfaceImpl(someDependency);
}
//and contribute our service to something else:
public static void contributeSomeOtherService(Configuration conf,
@InjectService("ServiceInterface") ServiceInterface someService) {
...
}
But all of this seemed sort of silly... if tapestry can figure out how
to inject services into builder methods, then it can figure out how to
inject them into constructors. It just needs to know which class to
associate with a particular interface. Thus was born "bind" and
constructor-based injection, and now our example looks like:
public static void bind(ServiceBinder binder) {
binder.bind(ServiceInterface.class,ServiceInterfaceImpl.class);//
with default service id of ServiceInterface.
}
//and contribute our service
public static void contributeSomeOtherService(Configuration conf,
@InjectService("ServiceInterface") ServiceInterface someService) {...}
The advantage of "bind" is that you can bind lots and lots and lots of
services inside of a single method. See
org.apache.tapestry5.services.TapestryModule for an example. Note
that somewhere along the way, tapestry's "intelligence" at figuring
out which services to inject increased, which made the @InjectService
bit unnecessary for many (but not all) cases.
This is fairly typical usage at present.
But... :) it turns out that there are plenty of times where you're
only going to reference a service one time: when you contribute it to
another service. This is the case, for example, with RequestFilter.
You're never going to directly inject your request filter
implementation into anything but the contribution to RequestHandler
(the pipeline that runs through all of the RequestFilters). In those
cases, why even both binding it? Wouldn't it be nice to just tell
tapestry: hey, I need this class instantiated, and any other IOC magic?
Thus was born @Autobuild, which shortens our example to:
public static void contributeSomeOtherService(Configuration conf,
@Autobuild ServiceInterfaceImpl impl) {...}
Now we're talking!
But, as long as we're at it... why should we have to have the method
parameter at all?
public static void
contributeSomeOtherService(Configuration<ServiceInterface> conf) {
conf.addInstance(ServiceInterfaceImpl.class);
}
Tapestry will find ServiceInterfaceImpl, instantiate it with all
dependencies, and add it to the configuration. If that class
specifies a "per thread" scope, then it's still per-thread (to the
best of my knowledge; I haven't tested this).
So, getting back to your request filter, you can simply do:
public static void
contributeRequestHandler(OrderedConfiguration<RequestFilter> filter) {
conf.addInstance("myfilter",MyRequestFIlter.class);
}
And you're done!
All of that is a long way of saying: there's no difference in outcome,
only in approach. Which approach you use depends entirely on what you
need.
If you're constructing a service that will be injected into many other
services, pages, etc., then you're going to use a builder method or
the service binder method.
If you're constructing a class that's going to be contributed to the
configuration of a single service, you may as well just use
"addInstance".
Now, I'm referencing another e-mail, but as long as I'm on the
subject... "per thread" services. 90% of the time, you don't need to
make your services per-thread. But if you do, you can specify that it
should be per thread by appropriately marking the service
implementation.
Your RequestFilter absolutely doesn't need to be per-thread. But it /
will/ use thread-specific information, and therefore utilize other
services which /are/ per-thread.
HttpServletRequest is a per-thread service in tapestry. Or, a
PerThread object. Tapestry handles storing the request into thread-
locale variables for you.
(Note that you can also inject the PerThreadManager to assist with
storing thread-specific data).
If you're using the tapestry-hibernate module, you get another per-
thread service for free: Session (a hibernate session), which is
created on demand and associated with the current thread for future
use within that thread.
You don't have to concern yourself with the details of how exactly the
per-thread coolness works; just know that it does.
So you can do:
public class AuthRequestFilter implements RequestFilter {
private final Session session;
private final HttpServletRequest hsrequest;
public AuthRequestFilter(Session session, HttpServletRequest
request) {
this.session = session;
this.hsrequest=request;
}
public boolean service(Request request, Response response,
RequestHandler handler) {
//look up user using the session.
//do whatever you need to do with the hsrequest.
//These services will "just work": You'll receive the data
associated with the current request.
return handler.service(request,response);
}
}
public static void
contributeRequestHandler(OrderedConfiguration<RequestFilter> conf) {
conf.addInstance("auth",AuthRequestFilter.class);
}
Apologies if this wound up being incoherent; getting late here.
HTH,
Robert
On Apr 9, 2009, at 4/911:49 PM , daniel joyce wrote:
Still confused. So buildMethods allow proxies/per-thread? But using
constructor style doesn't? Even if the class passed to autobuilding is
annotated per-thread?
On Thu, Apr 9, 2009 at 8:58 PM, Robert Zeigler <robe...@scazdl.org>
wrote:
Yes, build methods go in the app module.
RequestFilters: depends on how you build them, but if you construct
them as
a bonafide service (rather than autobuilding) they will be proxied,
and are
therefore elligible for "per thread scope".
That said, I've never used a per-thread RequestFilter. Rather, I
tend to
inject per-thread services into my RequestFilter implementation. For
example, ApplicationStateManager is a per-thread-scoped service. So
even
through my filter isn't per thread, it's accessing thread-specific
data when
it accesses data from the ApplicationStateManager service.
Robert
On Apr 9, 2009, at 4/99:52 PM , daniel joyce wrote:
Also, build methods go in the appmodule, right?
Guess it wasn't my final question. :)
Also, are RequestFilters per-Thread, or Singleton? Can they be
per-thread if needed?
-Daniel
On Thu, Apr 9, 2009 at 7:42 PM, daniel joyce <daniel.a.jo...@gmail.com
>
wrote:
I also found a HttpServletRequestFilter.
Thanks for the response, it helps to explain a lot.
I am finding my biggest problem is the documentation. I have
OReilley
safari access, and the Tapestry 5 book there leaves out about half
features. What is needed is a tapestry cookbook/recipe style thing.
How to make a service, How to make a filter.
One final question. In the document examples on service building,
sometimes the build method is called build, othertimes buildFoo
where
foo is the service being built. Which is correct, or does it
matter?
-Daniel
On Thu, Apr 9, 2009 at 7:10 PM, Robert Zeigler <robe...@scazdl.org>
wrote:
Autobuilder vs. builder vs. constructor:
Depends on your needs. These aren't mutually exclusive, either.
a) Tapestry's ioc container will attempt to use an
"ObjectLocator" to
fill
in the arguments to the constructor; one such object provider is a
service
injection provider.
So, though it used to be that you /had/ to specify
@InjectService on
constructor arguments, it's not so anymore. There are cases
where using
@InjectService with a specific service id is still useful (to
avoid
dependency recursion issues, for example). But often, you can
just put
the
service interface in and have it "work".
b) Builder: a builder method is useful when you're constructing
certain
types of services. For example, pipelines. You might use
tapestry's
pipeline builder service to build your pipeline for you, so you
don't
have
an actual "PipelineXImpl" class lying around; instead, you use a
builder
method to construct the service "on the fly".
c) Autobuilding - the ability to "autobuild" objects is very nice.
Typically, I use this when the object I'm building is /not/ a
"standalone
service" that I'm going to reference from somewhere else (not
something
that
will directly injected or contributed to). In that sense, the
CayenneRequestFilter could have been autobuilt, since I could
have done
a
"contributeRequestHandler(OrderedConfiguration<RequestFilter>
conf,
@Autobuild CayenneRequestHandler handler) {...}
I don't need to inject CayenneRequestHandler anywhere else, so
there's
no
real need to define it as a separate service. But @Autobuild
didn't
exist
when I wrote the module. ;)
If I were to write it today (or refactor it today), I would
probably use
@Autobuild for that one. Keep in mind that @Autobuild is going
to use
the
constructor parameters to determine what to inject*. :)
Regarding HttpServletRequest, if you need it directly, you can
inject
it, as
tapestry provides a thread-based proxy around it. Something like:
public MyRequestFilter implements RequestFilter {
private final HttpServletRequest servletRequest;
public MyRequestFilter(HttpServletRequest request) {
servletRequest = request;
}
public boolean service(Request request, Response response,
RequestHandler handler)
{
//do stuff with the servlet request.
return handler.service(request,response);
}
}
Robert
* Recently, field-based injection support was added for
services, so
this
isn't strictly true anymore. But I still prefer constructor
injection
for
services.
On Apr 9, 2009, at 4/95:54 PM , daniel joyce wrote:
How/where do I inject it? It's not obvious from the docs on
when/how I
should user autobuilder vs builder vs constructor.
The docs say you need to inject services explicitely inside the
constructor, yet the CayenneRequestFilter has a constructor w/o
Inject
annotations.
Also, the Tapestry 5 Request object supposedly wraps the
HttpServletRequest ( where remote user is set ), but provides
no way
to get the raw request, from which I can grab RemoteUser which
tells
me which user tomcat logged in.
-Daniel
On Thu, Apr 9, 2009 at 1:57 PM, daniel joyce <daniel.a.jo...@gmail.com
>
wrote:
Awesome, Thanks!
So far, the nice thing about Tapestry has been its very fluid
component based nature. I am so used to having to do things in a
certain order with other frameworks. Here, things are very
orthogonal,
and my reasoning about how to use Tapestry keeps improving.
-Daniel
On Thu, Apr 9, 2009 at 12:51 PM, Robert Zeigler <robe...@scazdl.org
>
wrote:
Here's a sample request filter that plays with application
state
objects
(which are backed by the http session):
http://code.google.com/p/tapestry5-cayenne/source/browse/trunk/tapestry5-cayenne-core/src/main/java/com/googlecode/tapestry5cayenne/services/CayenneRequestFilter.java
You can also use the tapestry-provided Request object (which
wraps
HttpServletRequest), which provides access to the wrapper
"Session"
object.
You can also directly inject HttpServletRequest.
Cheers,
Robert
On Apr 9, 2009, at 4/92:11 PM , daniel joyce wrote:
What about using a requestfilter? Any better docs on how to
implement
one? I see bits and pieces here and there, but nothing as
coherent
as
the Dispatcher howto.
-Daniel
On Thu, Apr 9, 2009 at 11:38 AM, daniel joyce
<daniel.a.jo...@gmail.com>
wrote:
I looked at spring security, and it required yet-another
annotation,
and annotating a class to protect it didn't protect the
methods as
well. This struck me as too hit-or-miss
With Tomcat, I can simply protect whole paths or pages, no
need to
worry about annotating a class, and then annotating each
method.
Bit
too fine-grained for my needs.
On Thu, Apr 9, 2009 at 11:00 AM, manuel aldana
<ald...@gmx.de>
wrote:
Maybe you should look at the tapestry-spring-security plugin
(http://www.localhost.nu/java/tapestry-spring-security/index.html
).
It
works
great and integrating is also not that difficult.
Good thing is that you can both secure by single page or
by page
folders.
Beware that it is not compatible with 5.1.x yet (works
only for
5.0.18).
daniel joyce schrieb:
So I want to use pages with context so that it is easily
bookmarkable.
My website uses a DataSourcerealm to determine which
pages can be
accessed by a user.
So normal flow is user logs in, first page he gets
directed to
sets
up
the User object as a ASO, other pages use this user.
But if he bookmarks a url with context, say
"configureProject/124332",
and he clickes on the bookmark, logs in to tomcat, and gets
redirected
to it, the User object may not have been initialized yet.
Now
configure project is fine, since it is mostly working with
projects.
But I want the user object to exist so that I confirm the
user
actually owns it.
Now I could have a basepage, whose onActivate() grabs the
auth'd
user
string from the Httpsession, runs a query, and either
sets up the
User
object, or bounces out the login page. And every other
page could
inherit from this one, and call super.OnActivate in their
onActivate
method.
But I was wondering, is there a service I can write that
can
examine
the HttpSession, and populate the User object. Is
HttpSession
available to services already? IE, can I inject it in the
usual
method
via my builder?
-Daniel
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
--
manuel aldana
ald...@gmx.de
software-engineering blog: http://www.aldana-online.de
---------------------------------------------------------------------
To unsubscribe, e-mail: users-
unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-
h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
For additional commands, e-mail: users-h...@tapestry.apache.org