Making services in Tapestry 5: No service implements the interface - maven

I'm developing my first Tapestry application with a login system based on a Hibernate database.
On one page with a session object, I want to call my Authenticator service class, which also gets the session injected and does some stuff. My problem is, I can't get any services to run, it's been very frustrating, despite me following simple guides like this one: http://code.google.com/p/shams/wiki/Service
In my services package, I got the Authenticator.java and AuthenticatorImpl.java interface and implemented class. In the AppModule class, I call
binder.bind(Authenticator.class, AuthenticatorImpl.class);
And in my page 'ShowAllUsers' I inject my Authenticator service object:
...
public class ShowAllUsers{
#Inject
private Session session;
#Inject
private Authenticator authenticator;
...
}
But when I load the page on my server, I receive following error:
org.apache.tapestry5.ioc.internal.OperationException
Error obtaining injected value for field de.webtech2.pages.user.ShowAllUsers.authenticator: No service implements the interface de.webtech2.services.Authenticator.
trace:
- Creating instantiator for component class de.webtech2.pages.user.ShowAllUsers
- Running component class transformations on de.webtech2.pages.user.ShowAllUsers
- Injecting field de.webtech2.pages.user.ShowAllUsers.authenticator
But my AppModule does bind the class to the interface successfully. In the Maven build console I can read "Authenticator: DEFINED" and if I try to bind it in another module, it complains because it's bound in AppMopule already.
Why doesn't tapestry see the implementation? What am I doing wrong?

Glad you checked the startup log output, that's certainly the first "sanity check" towards addressing this problem.
I think uklance has the right idea: do a clean build, make sure you don't have multiple classes named Authenticator floating around ... perhaps from a 3rd party library. I'm always having problems where I accidentally import a non-Tapestry class that happens to be named "Resource" or something.

I haven't solved the issue itself but I found a workaround that fixes it. As you might find on the internet, Tapestry allows for auto-reloading classes. Pages and components do work fine, services have some limitations -- this is where there seem to arise issues. Tomcat doesn't link the interface to the implementation.
Fix: A simple restart of eclipse solves this. Meh.
(This also fixes the "method not found" error if you added a new method to an existing service)
Also, when I execute mvn clean, everything gets screwed many times over. Eclipse can no longer resolve the simplest class and package references. Classes in the same package can no longer be found, or references to the javax.internet package lead into eternal nothingness -- whereas everything was working just fine a moment ago.
Fix:
Right-click eclipse project -> Properties -> Maven
Tick the checkbox for "Resolve dependencies from Workspace projects" and hit Apply.
If it is already checked, uncheck -> apply, then recheck -> apply. Eclipse should go sane again -- until next time...

Related

how to Resolve "could not initialize proxy - no session" error when using Spring repository

I'm working on a mutitenant project it maintains different schema for each tenant, followed Project
As we are dynamically switching the tenants so it looks like some configuration is missed which is closing the session or not keeping the session open to fetch the LAZY loaded objects. Which results in "could not initialize proxy - no session" error.
Please check below link to access the complete project and db schema scripts, please follow the steps given in Readme file.
Project
It will be helpful if someone can point out the issue in the code.
i tried to put service methods in #Transactional annotation but that didn't work.
I'm expecting it to make another call to the LAZY loaded object, This project is simplefied verson of the complex project, actually i have lot more lazy loaded objects.
Issue:-
I'm getting no Session error "could not initialize proxy [com.amran.dynamic.multitenant.tenant.entity.Tenant#1] - no Session"
at line 26 (/dynamicmultitenant/src/main/java/com/amran/dynamic/multitenant/tenant/service/ProductServiceImpl.java)
The issue is that your transaction boundaries are not correct. In TenantDatabaseConfig and MasterDatabaseConfig you've correctly added #EnableTransactionManagement, which will setup transactions when requested.
However - the outermost component that has an (implicit) #Transactional annotation is the ProductRepository (by virtue of it being implemented by the SimpleJpaRepository class - which has the annotation applied to it - https://github.com/spring-projects/spring-data-jpa/blob/864c7c454dac61eb602674c4123d84e63f23d766/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L95 )
and so your productRepository.findAll(); call will start a transaction, create a JPA session, run the query, close the session, close the transaction, which means that there is no longer any transaction / session open in which to perform the lazy-loading.
Therefore, your original attempt of
i tried to put service methods in #Transactional annotation but that didn't work.
IS the correct thing to do.
You don't say exactly what you tried to do, and where, but there are a few things that could have gone wrong. Firstly, make sure you're adding a org.springframework.transaction.annotation.Transactional and not a javax.transaction.Transactional annotation.
Secondly (and the more likely problem in this scenario), you'll need to configure the annotation with which transaction manager the transaction should be bound to, otherwise it may use an existing / new transaction created against the master DB connection, not the tenant one.
In this case, I think that:
#Service
#Transactional(transactionManager = "tenantTransactionManager")
public class ProductServiceImpl implements ProductService {
should work for you, and make all the methods of the service be bound to a transaction on the tenant DB connection.
EDIT: Answering a follow-up question:
can you please also suggest a better way to inject my tenantTransactionManager in all my service classes, as I don't want to mention tenantTxnManger in all service classes if there is any better way to do it ?
Yes, sure. You can create a meta-annotation that applies multiple other annotations, so you could create:
/**
* Marks class as being a service operating on a single Tenant
*/
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Service
#Transactional("tenantTransactionManager")
public #interface TenantService {
}
and then you can simply annotate your service classes with #TenantService instead of #Service:
#TenantService
public class ProductServiceImpl implements ProductService {

Spring Boot doesn't create Service bean and bypasses it's activity in Controller

Project structure:
Here is the repository (no class exceeds 20 lines of code): https://github.com/MoskovchenkoD/spring5-jokes
Here is the problem: Service implementation isn't used, and 'joke' attribute doesn't get printed on the page (just '123'). Controller's #RequestMapping method is simply ignored or bypassed.
How to fix it? I was following a step-by-step video from generating a project at start.spring.io to launching it.
Much appreciated!
Yet another childish error =(
I moved the Application class one level up and now it works fine.

Are services in AEM really singleton?

I have an interface which I have implemented. I have annoted the impl with #Component and #Service of the package org.apache.felix.scr.annotations.
I wrote a simple constructor for my impl
public MyImpl(){
LOG.info("New instance created!!");
}
I also added loggers in #activate and #deactivate method.
I expected to see "New instance created!!" only once BUT I can see activate and deactivate method being called per request I make on a page(This service is invoked by A Sling Model which is used in that page)
What I saw was "New instance created!!" logged several times.
This means the OSGi container create multiple instances of my Service and called the activate and deactivate method every time.
This shows that this is not a Singleton.
The Object should be discarded only when I uninstall my bundle.
Please help me understand what is going on here.
I WANT TO IMPLEMENT A TRUE SINGLETON IN AEM
I have implemented this in AEM 6.5 instance which uses Apache Felix.
Edit:
Adding Service properties:
aemRootUrl http://localhost:8080
api.http.connections_manager.timeout 60000
api.http.cookie_max.age 18000
api.http.max_connections 200
api.http.max_connections_per_host 20
api.http.timeout.connection 300000
api.http.timeout.socket 300000
api.server.ssl.trust_all_certs true
api.server.url https://10asdasdsad
api.server.username admin
component.id 3925
component.name com.example.foundation.core.connection.impl.HybrisConnectionImpl
non_akamai.api.server.url hadasdadasd
service.bundleid 585
Service PID com.example.foundation.core.connection.impl.HybrisConnectionImpl
service.scope bundle
Using Bundles com.example.dumb-foundation.core (585)
Values altered to hide client specific information
EDIT::
I've removed the SCR annotations and replaced them with OSGI annotations here I've explictly specified
#Component(service =HybrisConnection.class, immediate=true,scope = ServiceScope.SINGLETON)
But still is shows as scope=bundle.
Should I enforce Singleton and OSGi annotations on it's dependencies as well for this to be a proper Singleton?
In declarative services (which is what you use behind the scenes) there are some cases when a component (and its service) is unpublished.
By default a simple component with immediate=true will come up when the bundle starts and go down when it stops.
If your component has any mandatory service dependencies (#Reference) then it will only be active while all dependencies are present. So if at least one dependent service goes away the component will be deactivated.
In addition the component might get restarted when config is not present at start but added later. If you want to avoid this make the config required.
Every thing #Christian Schneider said is true.
They AEM services are Singletons but are deactivated/unpublished at times. This might be for various reasons.
I faced a horrible issue because of ConfigurationAdmin service. Using this services caused our OSGi config files to be bound to the wrong bundle i.e. SlingModels. bundle within AEM.
the only way to access this is by getting the service using configAdmin.getConfig(PID).setBundleLocation(null);
BUT Doing this causes the service that is linked to this configuration to restart.
So every time I did config.setBundleLocation(null) the service restarted.
The best and most awesome way to resolve this is use OCD to define configuration for OSGi Services linked to OSGi config.xmls
AND NEVER EVER EVER use configuration Admin
If you want to access properties of another service Say ServiceA want to read ServiceB's title property set in com.example.serivce.impl.ServiceB.xml
Then in ServiceB in the #activate method read the props from OCD config and set it in instance level and have ServiceA inject ServiceB as it's dependency and use the property needed.
eg.
class ServiceA{
#Reference
private ServiceB serviceB;
public void someMethod(){
serviceB.getTitle(); // Successfully read property of another service i.e.
ServiceB without using ConfigurationAdmin.
}
}

Executing extension before SpringExtension

I'm trying to implement integration testing in my app and have test class like that:
#ExtendWith(value={MyDockerExtension.class})
#ExtendWith(value={SpringExtension.class})
#WebAppConfiguration
#ContextConfiguration(classes={...})
#TestInstance(TestInstance.LifeCycle.PER_CLASS)
public class TestClass{ ... }
Is there any way to make MyDockerExtension execute some code, before whole SpringExtension start working and generate whole Context with Configurationc classes?
I've heard that order in which we declare extensions is the key, but sadly MyDockerExtension that implements BeforeAllCallback, AfterAllCallback executes right before test method and after whole context is loaded. In that situation it's to late to start containers with docker, becuase since whole context is loaded my app already tried to connect to the container.
At first I was skeptical about the order being fixed but you're correct:
Extensions registered declaratively via #ExtendWith will be executed in the order in which they are declared in the source code.
Regarding the MyDockerExtension, you may want to look at the extension point TestInstancePostProcessor, which is called before #BeforeAll. SpringExtension implements it and I guess it's there where it sets up the application context. If you also implement it, you should be able to act before it does.

Tapestry5 : No service implements the interface org.springframework.context.ApplicationContext

I'm using the Tapestry5 tapx template library to send an html email, as per this example.
When I run the example I get the following error:
Caused by: java.lang.RuntimeException: No service implements the interface org.springframework.context.ApplicationContext.
at org.apache.tapestry5.ioc.internal.RegistryImpl.getService(RegistryImpl.java:560)
at org.apache.tapestry5.ioc.internal.ObjectLocatorImpl.getService(ObjectLocatorImpl.java:44)
All the tapestry-* jars, including tapestry-spring-5.1.05.jar are in my classpath.
Any clues as to what I'm missing?
Figured it out. SpringIOC loads all modules it find on the classpath. The SpringModule, in tapestry-spring.jar, attempts to initialise the ApplicactionContext service, which causes the problem.
Removing tapestry-spring.jar from the classpath fixes the problem.
Follow the directions on the web site carefully; my guess is that you are not using the special TapestrySpringFilter (instead of the normal TapestryFilter).
It's been a while since I looked at this code; I can't remember if the ApplicationContext is exposed as a service or injectable object. Seems like it should be.
Fair enough; not sure what you situation is, but you should look in more detail at what TapestrySpringFilter does in terms of set up and replicate it into your standalone app's startup. There's some special bootstrapping magic that you will want to leverage.

Resources