Im trying to use CDI extensions to discover JAX-RS resources at runtime and automatically publish them under different base URIs in a Java SE environment. Applications should not need to extend javax.ws.rs.core.Application themselves if possible.
I have read RestEasy documentation and javadoc but failed to find any obvious way to modify the #ApplicationPath at runtime.
One idea that im exploring is to try generate javax.ws.rs.core.Application and set the #ApplicationPath base URI programmatically, maybe by using an AnnotatedType CDI extension, and publish that as a * org.jboss.resteasy.spi.ResteasyDeployment`.
Are there other/better ways to do this?
EDIT:
Trying CDI extension event ProcessAnnotatedType to change #javax.ws.rs.Path of JAX-RS resources.
<X> void process(#Observes ProcessAnnotatedType<X> pat) {
if (!pat.getAnnotatedType().isAnnotationPresent(javax.ws.rs.Path.class)) {
return;
}
final AnnotatedType<X> org = pat.getAnnotatedType();
AnnotatedType<X> wrapped = new AnnotatedType<X>() {
#Override
public <T extends Annotation> T getAnnotation(final Class<T> annotation) {
if (javax.ws.rs.Path.class.equals(annotation)) {
class PathLiteral extends AnnotationLiteral<javax.ws.rs.Path> implements javax.ws.rs.Path {
#Override
public String value() {
return "change_me/" + (javax.ws.rs.Path) org.getAnnotation(annotation);
}
}
return (T) new PathLiteral();
} else {
return org.getAnnotation(annotation);
}
}
pat.setAnnotatedType(wrapped);
}
... then after bootstrap, constructing the bean using javax.enterprise.inject.spi.BeanManager was expecting the following code to print "change_me/...."
Set<Bean<?>> beans = beanManager.getBeans(jaxrsClass);
for (Bean<?> bean : beans) {
CreationalContext cc = bm.createCreationalContext(bean);
Object jaxrs = bean.create(cc);
Path p = jaxrs.getClass().getAnnotation(Path.class);
System.out.println(p.value());
}
... but this does not work. javax.ws.rs.Path is unchanged for JAX-RS resource 'jaxrsClass'.
What is wrong?
I doubt this can be done in a reliable way. It probably all comes down to which happens first: the CDI bootstrap or JAX-RS, of course in the future or in other application servers it could all be done in parallel.
It's certainly a cool idea though. What have they said on the RestEasy forums?
We are already using such an approach.
We are using the feature to use Subresource locators and take the power of guice.
At the startup we are scanning the classpath for all resources annotated with #Path. After that we are extracting the path and binding the resources with the help of Names/#Named. So the resources can later be injected with the help of the name.
bind(..).annotatedWith(Names.named("path")).to(..)
The next step is that you need a resource with a subresource locator.
#Path("{name}")
public Object find(#PathParam("name") name){
return injector.getInstance(..);
}
You could use this approach to bind them at runtime and also to change the original annotated path.
Related
If you want to have another middleware/object in a middleware
you have to use a factory like
namespace App\Somnething;
use Interop\Container\ContainerInterface;
class MyMiddlewareFactory
{
public function __invoke(ContainerInterface $container, $requestedName)
{
return new $requestedName(
$container->get(\App\Path\To\My\Middleware::class)
);
}
}
So MyMiddleware would have been injected with \App\Path\To\My\Middleware and we would be able to access it.
Question:
would it be wrong to inject the middleware with the app itself or the container? Like:
namespace App\Somnething;
use Interop\Container\ContainerInterface;
use Zend\Expressive\Application;
class MyMiddlewareFactory
{
public function __invoke(ContainerInterface $container, $requestedName)
{
return new $requestedName(
$container->get(Application::class)
);
}
}
This way it would be possible to get anything ~on the fly.
Like
namespace App\Somnething;
use Zend\Expressive\Application;
class MyMiddleware
{
/** #var Application $app */
protected $app;
public function __construct(Application $app)
{
$this->app = $app;
}
public function __invoke($some, $thing)
{
if ($some and $thing) {
$ever = $this->app
->getContainer()
->get(\Path\To\What\Ever::class);
$ever->doSome();
}
}
}
You don't inject middleware into other middleware. You inject dependencies like services or repositories. Each middleware takes care of a specifc task like authentication, authorization, localization negotiation, etc. They are executed one after the other. They mess around with the request and pass the request to the next middleware. Once the middleware stack has been exhausted, the response is returned all the way back through all the middleware in reverse order until it finally reaches the outer layer which displays the output. You can find a flow overview in the expressive docs.
I wouldn't advice to inject the container and certainly not the app itself. Although it might be easy during development, your application becomes untestable. If you inject only the services that are needed into a middleware, action or service you can easily mock those during tests. After a while you get used to writing factories where needed and it goes pretty fast.
The same goes for injecting the entity manager (if you use doctrine). It's easier to test an application if you only inject the needed repositories, which you can easily mock.
Having said this, if you are looking for an easy way to inject dependencies, zend-servicemanager can do that. Take a look at abstract factories. With an abstract factory you can create one factory for all your action classes:
<?php
namespace App\Action;
use Interop\Container\ContainerInterface;
use ReflectionClass;
use Zend\ServiceManager\Factory\AbstractFactoryInterface;
class AbstractActionFactory implements AbstractFactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// Construct a new ReflectionClass object for the requested action
$reflection = new ReflectionClass($requestedName);
// Get the constructor
$constructor = $reflection->getConstructor();
if (is_null($constructor)) {
// There is no constructor, just return a new class
return new $requestedName;
}
// Get the parameters
$parameters = $constructor->getParameters();
$dependencies = [];
foreach ($parameters as $parameter) {
// Get the parameter class
$class = $parameter->getClass();
// Get the class from the container
$dependencies[] = $container->get($class->getName());
}
// Return the requested class and inject its dependencies
return $reflection->newInstanceArgs($dependencies);
}
public function canCreate(ContainerInterface $container, $requestedName)
{
// Only accept Action classes
if (substr($requestedName, -6) == 'Action') {
return true;
}
return false;
}
}
I wrote a blog post about that.
At the end of the day it's your own decision, but best practice is not injecting the app, container or the entity manager. It will make your life easier if you need to debug your middleware and / or write tests for it.
Injecting the application or container in your middleware is possible but it is not good idea at all:
1) Inversion Of Control (IoC)
It violated the inversion of control principle, your class must not have any knowledge about the IoC container.
2) Dependency Inversion Principle (DIP)
Dependency inversion principle states that "high-level modules should not depend on low-level modules", so your higher level middleware class depends on the infrastructure/framework.
3) Law of Demeter (LoD)
According to the law of demeter, the unit should have limited knowledge about other units, it should know only about its closely related units.
The MyMiddleware::class has too much knowledge other units, first of all, it knows about the Application::class, then it knows that the Application knows about the Container, then it knows that the Container knows about the What\Ever::class and so on.
This kind of code violates some of the most important OOP principles, leads to horrible coupling with the framework, it has implicit dependencies and least but not last, it is hard to be read and understood.
We are trying to provide a clean URI structure for external endpoints to pull json information from CQ5.
For example, if you want to fetch information about a particular users history (assuming you have permissions etc), ideally we would like the endpoint to be able to do the following:
/bin/api/user/abc123/phone/555-klondike-5/history.json
In the URI, we would specifying /bin/api/user/{username}/phone/{phoneNumber}/history.json so that it is very easy to leverage the dispatcher to invalidate caching changes etc without invalidating a broad swath of cached information.
We would like to use a sling servlet to handle the request, however, I am not aware as to how to put variables into the path.
It would be great if there were something like #PathParam from JaxRS to add to the sling path variable, but I suspect it's not available.
The other approach we had in mind was to use a selector to recognise when we are accessing the api, and thus could return whatever we wanted to from the path, but it would necessitate a singular sling servlet to handle all of the requests, and so I am not happy about the approach as it glues a lot of unrelated code together.
Any help with this would be appreciated.
UPDATE:
If we were to use a OptingServlet, then put some logic inside the accepts function, we could stack a series of sling servlets on and make the acceptance decisions from the path with a regex.
Then during execution, the path itself can be parsed for the variables.
If the data that you provide comes from the JCR repository, the best is to structure it exactly as you want the URLs to be, that's the recommended way of doing things with Sling.
If the data is external you can create a custom Sling ResourceProvider that you mount on the /bin/api/user path and acquires or generates the corresponding data based on the rest of the path.
The Sling test suite's PlanetsResourceProvider is a simple example of that, see http://svn.apache.org/repos/asf/sling/trunk/launchpad/test-services/src/main/java/org/apache/sling/launchpad/testservices/resourceprovider/
The Sling resources docs at https://sling.apache.org/documentation/the-sling-engine/resources.html document the general resource resolution mechanism.
It is now possible to integrate jersy(JAX-RS) with CQ. We are able to create primitive prototype to say "Hello" to the world.
https://github.com/hstaudacher/osgi-jax-rs-connector
With this we can use the #PathParam to map the requests
Thanks and Regards,
San
There is no direct way to create such dynamic paths. You could register servlet under /bin/api/user.json and provide the rest of the path as a suffix:
/bin/api/user.json/abc123/phone/555-klondike-5/history
^ ^
| |
servlet path suffix starts here
then you could parse the suffix manually:
#SlingServlet(paths = "/bin/api/user", extensions = "json")
public class UserServlet extends SlingSafeMethodsServlet {
public void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) {
String suffix = request.getRequestPathInfo().getSuffix();
String[] split = StringUtils.split(suffix, '/');
// parse split path and check if the path is valid
// if path is not valid, send 404:
// response.sendError(HttpURLConnection.HTTP_NOT_FOUND);
}
}
The RESTful way to approach this would be to have the information stored in the structure that you want to use. i.e. /content/user/abc123/phone/555-klondike-5/history/ would contain all the history nodes for that path.
In that usage. you can obtain an out of the box json response by simply calling
/content/user/abc123/phone/555-klondike-5/history.json
Or if you need something in a specific json format you could use the sling resource resolution to use a custom json response.
Excited to share this! I've worked ~ a week solving this, finally have the best Answer.
First: Try to use Jersey
The osgi-jax-rs-connector suggested by kallada is best, but I couldn't get it working on Sling 8. I lost a full day trying, all I have to show for it are spooky class not found errors and dependency issues.
Solution: The ResourceProvider
Bertrand's link is for Sling 9 only, which isn't released. So here's how you do it in Sling 8 and older!
Two Files:
ResourceProvider
Servlet
The ResourceProvider
The purpose of this is only to listen to all requests at /service and then produce a "Resource" at that virtual path, which doesn't actually exist in the JCR.
#Component
#Service(value=ResourceProvider.class)
#Properties({
#Property(name = ResourceProvider.ROOTS, value = "service/image"),
#Property(name = ResourceProvider.OWNS_ROOTS, value = "true")
})
public class ImageResourceProvider implements ResourceProvider {
#Override
public Resource getResource(ResourceResolver resourceResolver, String path) {
AbstractResource abstractResource;
abstractResource = new AbstractResource() {
#Override
public String getResourceType() {
return TypeServlet.RESOURCE_TYPE;
}
#Override
public String getResourceSuperType() {
return null;
}
#Override
public String getPath() {
return path;
}
#Override
public ResourceResolver getResourceResolver() {
return resourceResolver;
}
#Override
public ResourceMetadata getResourceMetadata() {
return new ResourceMetadata();
}
};
return abstractResource;
}
#Override
public Resource getResource(ResourceResolver resourceResolver, HttpServletRequest httpServletRequest, String path) {
return getResource(resourceResolver , path);
}
#Override
public Iterator<Resource> listChildren(Resource resource) {
return null;
}
}
The Servlet
Now you just write a servlet which handles any of the resources coming from that path - but this is accomplished by handling any resources with the resource type which is produced by the ResourceProvider listening at that path.
#SlingServlet(
resourceTypes = TypeServlet.RESOURCE_TYPE,
methods = {"GET" , "POST"})
public class TypeServlet extends SlingAllMethodsServlet {
static final String RESOURCE_TYPE = "mycompany/components/service/myservice";
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
final String [] pathParts = request.getResource().getPath().split("/");
final String id = pathParts[pathParts.length-1];
response.setContentType("text/html");
PrintWriter out = response.getWriter();
try {
out.print("<html><body>Hello, received this id: " + id + "</body></html>");
} finally {
out.close();
}
}
}
Obviously your servlet would do something much more clever, such as process the "path" String more intelligently and probably produce JSON.
EntityManagerFactory can be created without a persistence unit xml using
org.eclipse.persistence.jpa.PersistenceProvider {
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info,
java.util.Map properties)
}
but what is the implementation class of javax.persistence.spi.PersistenceUnitInfo in eclipselink
I am struggling on this problem too. I think that a PersistenceUnitInfo must be provided by the container(i.e. Application Server). It means that Eclipselink do not create one itself. If you are using Spring ORM, it uses a DefaultPersistenceUnitManager and call its obtainPersistenceUnitInfo(String unitName) method to get a instance of PersistenceUnitInfo. The unitName must be defined in persistence.xml. This means that you still needs an xml file.
By digging into the source code of Spring ORM, I found that Spring provides several implementations of PersistenceUnitInfo. In fact they are generally a Java Bean. You may be interested in SmartPersistenceInfo, MutablePersistenceInfo and SpringPersistenceUnitInfo. View them on Github.
EDIT:
I found the implementation of Eclipselink: It's SEPersistenceUnitInfo in org.eclipse.persistence.internal.jpa.deployment. Also found the method that reads every persistence unit in the configuration xml file.
public static Set<SEPersistenceUnitInfo> getPersistenceUnits(ClassLoader loader, Map m, List<URL> jarFileUrls) {
String descriptorPath = (String) m.get(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML);
if(descriptorPath == null) {
descriptorPath = System.getProperty(PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML, PersistenceUnitProperties.ECLIPSELINK_PERSISTENCE_XML_DEFAULT);
}
Set<Archive> archives = findPersistenceArchives(loader, descriptorPath, jarFileUrls);
Set<SEPersistenceUnitInfo> puInfos = new HashSet();
try {
for(Archive archive : archives) {
List<SEPersistenceUnitInfo> puInfosFromArchive = getPersistenceUnits(archive, loader);
puInfos.addAll(puInfosFromArchive);
}
} finally {
for(Archive archive : archives) {
archive.close();
}
}
return puInfos;
}
Java EE platform spec 6 says : the container is responsible for finding persistence.xml condensing the information into PersistenceUnitInfo and supplying that with a call to createContainerEntityManagerFactory.
PersistenceUnitInfo is defined by the Spec, refer to the JPA spec code or JavaDoc for its implementation.
http://www.eclipse.org/eclipselink/api/2.5/javax/persistence/spi/PersistenceUnitInfo.html
I need to modify an existing web app to use Castle.Windsor as IOC container. It was originally developed with StructureMap.
I am stuck with the following problem.
Lets say I have registered a couple of interfaces and their corresponding implementations:
IFoo -> Foo
IBar -> Bar
Calling container.Resolve<IFoo>() or container.Resolve<IBar>() works just fine. This means that the services are registered correctly.
I have a Web Api class with dependencies on other services, such as IFoo
public class BadRequestErrorHandler : HttpErrorHandler
{
// services
public BadRequestErrorHandler(IFoo foo) {...} // has dependency on IFoo
}
In StructureMap I can call:
var test = ObjectFactory.GetInstance<BadRequestErrorHandler>();
this will resolve the IFoo dependency.
Now this does not work with windsor.
How can this be achieved with windsor?
Thanks!
* EDIT *
I was just able to make it work by explicitely registering the BadRequestErrorHandler.
container.Register(Component.For<BadRequestErrorHandler>());
I am just hoping there is a better way to achieve this, that does not involve registering classes that have dependencies. I have a bunch of them...
* EDIT 2 **
To ease the pain, I added a special method to deal with these concrete types.
public T GetInstanceWithAutoRegister<T>()
{
if (container.Kernel.GetHandler(typeof(T)) == null)
{
container.Register(Component.For<T>());
}
return container.Resolve<T>();
}
public object GetInstanceWithAutoRegister(Type pluginType)
{
if (container.Kernel.GetHandler(pluginType) == null)
{
container.Register(Component.For(pluginType));
}
return container.Resolve(pluginType);
}
not ideal, but at least better than having to explicetly register each type. Hope someone has a better solution
You can achieve what you want by registering an ILazyComponentLoader which is a hook that gets called by Windsor as a "last resort" when a component cannot be resolved.
In your case, the implementation would probably look somewhat like this:
public class JustLetWindsorResolveAllConcreteTypes : ILazyComponentLoader
{
public IRegistration Load(string key, Type service)
{
return Component.For(service);
}
}
-and then it should be registered as such:
container.Register(Component.For<ILazyComponentLoader>()
.ImplementedBy<JustLetWindsorResolveAllConcreteTypes>());
You can read more about it in the docs.
I'm currently using SOA, I've a bunch of Service, (ArticleService, CommentService, UserService, etc..)
I also have a ConfigurationService which is filled from an XML configuration file.
I'm using Zend Framework.
THis configuration service is needed in some of my service, and I'm using dependency injection, is it a good practice, to add ConfigurationService in constructor of most my Service to be able to fetch global configuration?
Thank you for your feedbacks.
I would say, no, don't pass the config container - neither as a service nor as an array nor a Zend_Config instance - in the constructor of your other services. I would keep the injection (whether by constructor or by setter) for those services focused on the actual objects/collaborators/data they actually need.
So, for example, an ArticleService might depend upon an ArticleRepository interface/object or on an ArticleMapper or on a db adapter. Let the constructor/setter signatures for the ArticleService reflect what it truly needs.
Instead, what I would do is during Bootstrap, create some kind of factory object - perhaps as an application resource - that accepts in its constructor your config data/object/service (or even better, the bootstrap instance itself, from which you could get, not just your config data, but also any application resources, like a db adapter, that were created during the bootstrap process). Then write methods on your factory object that create/deliver the other services you need. Internally, the factory maintains a registry of already created services so that it can lazy-create instances where required.
A snippet of what I have in mind might be as follows:
Bootstrap snippet:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initFactory()
{
$factory = new My_Factory($this);
return $factory;
}
}
Then the factory:
class My_Factory
{
protected $_registry;
protected $_bootstrap;
public function __constructor($bootstrap)
{
$this->_bootstrap = $bootstrap;
}
public function getDbAdapter()
{
if (!isset($this->_registry['dbAdapter']){
$this->_bootstrap->bootstrap('db'); // probably using app resource
$this->_registry['dbAdapter'] = $This->_bootstrap->getResource('db');
}
return $this->_registry['dbAdapter'];
}
public function getArticleService()
{
if (!isset($this->_registry['articleService']){
$dbAdapter = $this->getDbAdapter();
$this->_registry['articleService'] = new My_ArticleService($dbAdapter);
}
return $this->_registry['articleService'];
}
public function getTwitterService()
{
if (!isset($this->_registry['twitterService']){
$options = $this->_bootstrap->getOptions();
$user = $options['twitter']['user'];
$pass = $options['twitter']['pass'];
$this->_registry['twitterService'] = new My_TwitterService($user, $pass);
}
return $this->_registry['twitterService'];
}
}
Then in a controller, you could grab an ArticleService instance:
class SomeController extends Zend_Controller_Action
{
protected $_factory;
public function init()
{
$this->_factory = $this->getInvokeArg('bootstrap')->getResource('factory');
}
public function someAction()
{
$articleService = $this->_factory->getArticleService();
$this->view->articles = $articleService->getRecentArticles(5); // for example
}
}
The upshot here is that each service explicitly identifies the collaborators it needs and the factory is a single place that takes care of creating/injecting all those collaborators.
Finally, I confess that I am just spitballing here. To me, this is essentially a rudimentary dependency injection container; in that sense, using a fully-featured DIC - perhaps the Symfony DIC or the new Zend\Di package in ZF2 - might be better. But after many months of struggling with all the best-practice recommendations to inject your dependencies, this is what I have come up with. If it's goofy or just plain wrong, please (please!) straighten me out. ;-)